我的程序从用户那里获得了两个 bool 变量,它们的值此后将不会改变。每个 bool 变量都启用一部分代码。像这样的东西:
#include <iostream>
void callback_function(bool task_1, bool task_2, bool task_3) {
if (task_1) {
std::cout << "Running task 1" << std::endl;
}
if (task_2) {
std::cout << "Running task 2" << std::endl;
}
if (task_3) {
std::cout << "Running task 3" << std::endl;
}
}
int main() {
bool task_1 = true;
bool task_2 = false;
bool task_3 = true;
while (true) {
callback_function(task_1, task_2, task_3);
}
return 0;
}
现在我的问题是,由于每次程序调用
callback_function()
时 bool 变量都是固定的,有没有办法避免回调函数中的if
语句?这是避免运行时检查的一种方法(为 bool 变量的所有排列实现回调函数---仅在以下两种情况下显示):
#include <functional>
#include <iostream>
void callback_function_for_tasks_1_2_3() {
std::cout << "Running task 1" << std::endl;
std::cout << "Running task 2" << std::endl;
std::cout << "Running task 3" << std::endl;
}
void callback_function_for_tasks_1_3() {
std::cout << "Running task 1" << std::endl;
std::cout << "Running task 3" << std::endl;
}
int main() {
bool task_1 = true;
bool task_2 = false;
bool task_3 = true;
std::function<void()> callback_function;
if (task_1 && task_2 && task_3) {
callback_function = callback_function_for_tasks_1_2_3;
} else if (task_1 && !task_2 && task_3) {
callback_function = callback_function_for_tasks_1_3;
}
while (true) {
callback_function();
}
return 0;
}
问题是,如果有
2^n
bool 变量,我必须实现n
不同的回调函数。有没有更好的方法可以做到这一点? 最佳答案
确保在编译时评估if语句
C++ 17引入了if constexpr
,它可以做到这一点:
template<bool task_1, bool task_2, bool task_3>
void callback_function() {
if constexpr (task_1) {
std::cout << "Running task 1" << std::endl;
}
if constexpr (task_2) {
std::cout << "Running task 2" << std::endl;
}
if constexpr (task_3) {
std::cout << "Running task 3" << std::endl;
}
}
如果启用了优化,则不需要
if constexpr
。 即使您使用常规的if
而不是if constexpr
,因为现在已经对 bool 进行了模板化,所以编译器将能够完全消除if
语句,而只需运行任务即可。 If you look at the assembly produced here,即使在-O1
上,您也会看到,任何callback
函数中都没有if语句。现在,我们可以直接将
callback_function
用作函数指针,避免使用function<void()>
:int main() {
using callback_t = void(*)();
callback_t func = callback_function<true, false, true>;
// Do stuff with func
}
我们还可以通过将
bool
分配给constexpr变量来命名它们:int main() {
using callback_t = void(*)();
constexpr bool do_task1 = true;
constexpr bool do_task2 = false;
constexpr bool do_task3 = true;
callback_t func = callback_function<do_task1, do_task2, do_task3>;
// Do stuff with func
}
自动创建所有可能的回调函数的查找表
您提到了在运行时在不同的回调函数之间进行选择。我们可以使用查找表轻松完成此操作,并且可以使用模板自动创建所有可能的回调函数的查找表。
第一步是从特定索引获取回调函数:
// void(*)() is ugly to type, so I alias it
using callback_t = void(*)();
// Unpacks the bits
template<size_t index>
constexpr auto getCallbackFromIndex() -> callback_t
{
constexpr bool do_task1 = (index & 4) != 0;
constexpr bool do_task2 = (index & 2) != 0;
constexpr bool do_task3 = (index & 1) != 0;
return callback_function<do_task1, do_task2, do_task3>;
}
一旦做到这一点,我们就可以编写一个函数来根据一堆索引创建一个查找表。我们的查询表将只是一个
std::array
。// Create a std::array based on a list of flags
// See https://en.cppreference.com/w/cpp/utility/integer_sequence
// For more information
template<size_t... Indexes>
constexpr auto getVersionLookup(std::index_sequence<Indexes...>)
-> std::array<callback_t, sizeof...(Indexes)>
{
return {getCallbackFromIndex<Indexes>()...};
}
// Makes a lookup table containing all 8 possible callback functions
constexpr auto callbackLookupTable =
getVersionLookup(std::make_index_sequence<8>());
在这里,
callbackLookupTable
包含所有8种可能的回调函数,其中callbackLookupTable[i]
扩展了i
的位以获取回调。例如,如果i == 6
,则i
的位是二进制的110
,因此callbackLookupTable[6]
是callback_function<true, true, false>
在运行时使用查找表
使用查找表非常简单。我们可以通过移位从一串
bool
中获取索引:callback_t getCallbackBasedOnTasks(bool task1, bool task2, bool task3) {
// Get the index based on bit shifting
int index = ((int)task1 << 2) + ((int)task2 << 1) + ((int)task3);
// return the correct callback
return callbackLookupTable[index];
}
演示如何读入任务的示例
我们现在可以在运行时获取
bool
,只需调用getCallbackBasedOnTasks
即可获取正确的回调int main() {
bool t1, t2, t3;
// Read in bools
std::cin >> t1 >> t2 >> t3;
// Get the callback
callback_t func = getCallbackBasedOnTasks(t1, t2, t3);
// Invoke the callback
func();
}
关于c++ - 如何避免对编译后无法访问的正在运行的代码部分进行运行时检查?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55438306/