强制恒定表达期间编译时进行评估?(Forcing a constant expression to

2019-07-18 03:12发布

前几天我问了由标准编译器来决定是否,计算在编译时constexpr功能。

什么时候一个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;
}

如果我被告知是真的,此代码示例是非常impratical,因为foobar的不采取constexpr(你不能使用consexpr的参数出于某种原因),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)));

尽管它只是罚款的事实,我觉得好像有什么东西是不正确的了。 是否创建一个匿名拉姆达影响性能? 是否通过右值引用返回实际上表达移到函数参数? 怎样的std ::举动冲击性能? 对此有一个更好的班轮解决方案?

Answer 1:

只是为了不让它埋在评论:

#include <type_traits>

#define COMPILATION_EVAL(e) (std::integral_constant<decltype(e), e>::value)

constexpr int f(int i){return i;}

int main()
{
    int x = COMPILATION_EVAL(f(0));
}

EDIT1:

这种方法的一个警告, constexpr函数可以接受浮点和被分配到constexpr浮点变量,但你不能使用浮点类型作为非类型模板参数。 此外,对于其他类型的文字的相同限制。

你拉姆达将工作,但我猜你会需要一个默认的捕捉得到有意义的错误消息,当非constexpr东西得到传递给函数。 这结束std::move是可有可无的。

EDIT2:

犯错,你的拉姆达方法并没有为我工作,我才意识到,它怎么连工作,拉姆达不是constexpr功能。 它不应该为你工作了。

这似乎真的没有办法解决,但初始化constexpr在局部范围变量。

EDIT3:

哦,好吧,是我不好,拉姆达的目的就是评估。 所以,它的工作了点。 其结果是,取而代之的,是其不可用跟随另一个编译时间EVAL。

EDIT4:

上C ++ 17, lambda表达式现在可以在使用constexpr上下文 ,所以在EDIT2 / EDIT3中提到的限制被移除! 因此,拉姆达的解决方案是正确的。 看到这个评论的更多信息。



文章来源: Forcing a constant expression to be evaluated during compile-time?