6

我想比较元编程和 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

4 回答 4

9

我相信原因是constexpr不能保证在编译时执行。要强制执行编译时评估,您必须将其分配给编译时别名。喜欢,

enum {i = fib(NUM)};

于 2013-12-19T13:30:41.747 回答
4

至少,使用 gcc,您可以通过将 constexpr 设置为静态变量来获取要在编译时计算的值:

static const unsigned fibNUM = fib(NUM);

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

于 2013-12-19T13:53:23.527 回答
1

一个简单的测试,看看你constexpr是否真的在编译时完成是使用std::array

#include <array>

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

gcc 没有任何抱怨

请参阅Bjarne Stroustrup 的评论

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

于 2013-12-19T13:37:14.100 回答
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;
于 2013-12-19T13:50:50.877 回答