【发布时间】:2013-10-13 20:06:42
【问题描述】:
我想使用模板进行优化,如here 所述。但是,随着 bool 模板参数数量的增加,实例化模板可能有太多的分支。如果你使用更大的枚举而不是布尔值,它会变得更加复杂。
#include <iostream>
using namespace std;
template <bool b1, bool b2>
int HeavyLoop_impl(int arg)
{
for (int i = 0; i < 10000000; i++)
{
// b1 is known at compile-time, so this branch will be eliminated
if (b1) { arg += 1; }
else { arg += 2; }
// b2 is known at compile-time, so this branch will be eliminated
if (b2) { arg += 10; }
else { arg += 20; }
}
return arg;
}
// This function could be generated automatically
void HeavyLoop(bool b1, bool b2, int arg)
{
int res;
if (b1) {
if (b2) { res = HeavyLoop_impl<true, true>(arg); }
else { res = HeavyLoop_impl<true, false>(arg); }
} else {
if (b2) { res = HeavyLoop_impl<false, true>(arg); }
else { res = HeavyLoop_impl<false, false>(arg); }
}
cout << "res: "<<res<<endl;
}
int main(int argc, char**argv)
{
bool b1 = true;
bool b2 = false;
int arg = 0;
HeavyLoop(b1, b2, arg);
return 0;
}
有没有办法自动生成HeavyLoop函数?我想要这样的东西:
vars_to_template_function<bool, bool>(HeavyLoop_impl, b1, b2, arg);
这有可能吗?感谢您的任何提示。
注意:这只是一个非常简化的例子。实际的循环当然更复杂:o)
【问题讨论】:
-
您的问题中有几个令人不安的地方。首先 b1 和 b2 在 main 中有硬编码值,所以即使不是模板,代码也会被优化掉,并且会直接调用右分支(假设你有一个下降编译器)。相反,如果 main 中的 b1 和 b2 是动态值,那么使用模板函数绝对没有优势,因为在 HeavyLoop 中无论如何都会进行分支......
-
这与链接并不真正匹配,因为它具有完全不同的代码,具体取决于标志。
-
@log0 除了在
HeavyLoop中,分支是由编译时已知的模板参数完成的,因此实际上不会发生分支。这就是问题的重点 - 将运行时知识(两个布尔值)转换为编译时(从 4 个具有硬编码分支的函数之一中选择)。 -
用Boost.preprocessor应该可以生成这样的“驱动”函数,但是我现在没时间自己尝试,抱歉。
-
HeavyLoop_impl是否如此繁重以至于编译器拒绝将其内联到main中?您实际上不必执行任何这些操作,优化器将知道b1和b2的值 对于该调用 一旦调用被内联,因为参数的值在编译时间(这是一个微不足道的数据流分析,表明它们在初始化后没有被修改,并且初始化来自编译时间常数)。然后它可以从内联到main的代码中消除死代码。