考虑以下两个片段:
// Option (1).
boost::mp11::mp_with_index<N>(i,
[&](const auto i){ function<i>(/* args... */); });
和
// Option (2).
inline static const std::array<std::function<void(/* Args... */)>, N>
functionArray{function<0>, ..., function<N-1>};
functionArray[i](/* args... */);
哪里N
是大约在 [0, 20], i
范围内的编译时间大小是 0
之间的运行时索引和N-1
,和template <size_t I> function(/* Args... */)
是具有已知签名的模板函数。 这两个选项中哪一个最快?
注意:我知道boost::mp11::mp_with_index
基本上创建了一个 switch 语句,允许将运行时索引转换为编译时索引。这引入了一些间接性,但我预计这不会太昂贵。同样,我知道std::function
由于类型删除引入了一些间接性。我的问题是:两种间接类型中哪一种最有效?
最佳答案
std::array<std::function<void(Args...)>, N>
与纯指针数组相比,可能会引入一些开销 std::array<void(*)(Args...), N>
.
查看生成的程序集 https://godbolt.org/z/a8z9aKs7P ,可以得出以下结论:
boost::mp11::mp_with_index
被编译为一个分支表,其中包含 N 个不同指令的 N 个地址,这些指令只需调用 function<I>
当跳到。因此,它会在分支表中查找地址,跳转到该地址,然后再次跳转到所需的函数。
这个分支表可以通过简单地存储 function<I>
的地址来简化。 ,只需要一跳。当您有一个函数指针数组时,就会发生这种情况,该数组本质上是一个分支表。
std::function
类似,但调用 std::function
比调用常规函数指针稍微复杂一些。
注意 clang 在 -O2
的优化方面很糟糕甚至-O3
。 boost::mp11::mp_with_index<N>
实际上是一堆 if/else 语句,应该很容易编译,就像 switch
一样。 ,但 clang 未能做到这一点(并留下 N
“比较和条件跳转”指令)。函数指针数组是这里唯一好的选择。
关于c++ - boost::mp11::mp_with_index 与 std::function 数组的性能比较,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70494728/