几天前,我问编译器根据哪些标准决定是否在编译期间计算 constexpr 函数。
事实证明, constexpr 仅在编译时评估,如果所有参数都是常量表达式并且您分配给它的变量也是常量表达式。
template<typename base_t, typename expo_t>
constexpr base_t POW(base_t base, expo_t expo)
{
return (expo != 0 )? base * POW(base, expo -1) : 1;
}
template<typename T>
void foobar(T val)
{
std::cout << val << std::endl;
}
int main(int argc, char** argv)
{
foobar(POW((unsigned long long)2, 63));
return 0;
}
如果我被告知是真的,那么这个代码示例是非常不切实际的,因为 foobar 不采用 constexpr(由于某种原因,您不能将 constexpr 用于参数),POW 在运行时被评估,即使它本来是可能的在编译时计算它。强制编译时评估的明显解决方案是:
auto expr = POW((unsigned long long)2, 63);
foobar(expr);
然而,这迫使我使用额外的代码行,每次我想确保在编译时评估 constexpr 时都不需要这样做。为了让这更方便一点,我想出了以下可疑的宏:
#define FORCE_CT_EVAL(func) [](){constexpr auto ___expr = func; return std::move(___expr);}()
foobar(FORCE_CT_EVAL(POW((unsigned long long)2, 63)));
尽管它工作得很好,但我觉得好像有些不对劲。创建匿名 lambda 会影响性能吗?通过右值引用返回是否实际上将表达式移动到函数参数?std::move 如何影响性能?有没有更好的单班轮解决方案?