constexpr函数在编译时不计算值

时间:2013-12-19 13:23:54

标签: c++ c++11 template-meta-programming compile-time gcc4.8

我想比较元编程和c ++ 0x中constexpr的使用。 然后我在两个模型中写了一个fib函数。 当我使用元编程模型时,答案打印速度非常快,因为它是在编译时计算的。但是当我使用constexpr函数时,它会在运行时计算值,而不是在编译时。 我使用g ++(gcc)4.8。可以帮助我吗?

#include <iostream>
using namespace std;
#define NUM 42

template <unsigned int N>
struct Fibonacci {
    enum { value = Fibonacci<N - 1>::value + Fibonacci<N - 2>::value };
};

template <>
struct Fibonacci<1> {
    enum { value = 1 };
};

template <>
struct Fibonacci<0> {
    enum { value = 1 };
};

constexpr unsigned int fib(unsigned int n)
{
    return (n > 1 ? fib(n-1) + fib(n-2) : 1 );
}

int main()
{

    cout << "Meta_fib(NUM)      : " << Fibonacci<NUM>::value << endl; // compile time :)
    cout << "Constexpr_fib(NUM) : " << fib(NUM) << endl;        // run time :-?
    return 0;
}

4 个答案:

答案 0 :(得分:9)

我认为原因是constexpr无法保证在编译时执行。要强制执行编译时评估,必须将其分配给编译时别名。像,

enum {i = fib(NUM)};

答案 1 :(得分:4)

至少使用gcc,你可以通过使它成为一个静态变量来获得在编译时计算的constexpr值:

static const unsigned fibNUM = fib(NUM);

当我阅读标准时,它仍然允许在启动时计算值,但实际上它将在编译时计算。

答案 2 :(得分:1)

查看您的constexpr是否真的在编译时完成的简单测试是使用std::array

#include <array>

std::array<int, Fibonacci<5>::value> arr;
std::array<int, fib(5)> arr2;

gcc has no complaints

请参阅此comment by Bjarne Stroustrup

  

...根据标准,可以评估constexpr函数   编译器时间或运行时间,除非它用作常量表达式,   在这种情况下,它必须在编译时进行评估。保证   编译时评估,我们必须使用它在一个常量   表达是必需的(例如,作为数组绑定或作为案例标签)或   用它来初始化constexpr。我希望没有自尊心   编译器会错过优化机会来做我的事情   最初说:“如果在编译时评估constexpr函数   它的所有参数都是常量表达式。“

答案 3 :(得分:1)

constexpr无法保证在编译时进行评估。这意味着,编译器可以选择是在编译时还是在运行时进行求值。 您可以尝试将其分配给编译时常量并像这样检查...

const long i = fib(NUM);// here i should be initialized at the time of 
                        // declaration
cout << "Meta_fib(NUM)      : " << Fibonacci<NUM>::value << endl; 
cout << "Constexpr_fib(NUM) : " << i << endl;