2013-12-19 4 views
6

Я хочу сравнить мета-программирование и использование constexpr в C++ 0x. , тогда я пишу функцию fib в обеих моделях. Когда я использую модель метапрограмм, ответ распечатывается очень быстро, потому что он вычисляется во время компиляции. но когда я использую функцию constexpr, он вычисляет значение во время выполнения, а не во время компиляции. Я использую g ++ (gcc) 4.8. Может ли кто-нибудь помочь мне?Функция constexpr не вычисляет значение во время компиляции

#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; 
} 
+0

[Оба выглядят время компиляции для меня.] (Http://coliru.stacked-crooked.com/a/5fe7e66ca805e846) – chris

+0

Не идея constexpr заключается в том, что она работает во время компиляции? –

+8

Как вы знаете, что он вычисляет значение во время выполнения? Вы посмотрели на сборку? – juanchopanza

ответ

9

Я считаю, что причина заключается в том, что constexpr не гарантирует выполнение во время компиляции. Чтобы обеспечить оценку времени компиляции, вы должны назначить ее псевдонимам компиляции. Мол,

enum {i = fib(NUM)};

+0

Любой способ заставить его быть оцененным по силе даже не назначать переменную const? – jayatubi

+0

Не уверен, что правильно понял вопрос.Вы просите еще один способ гарантировать оценку времени компиляции, кроме использования его в контексте «const»? Ответ на этот вопрос, вероятно, «Нет». –

+0

Например, я хочу передать результат функции 'constexpr' (A) в качестве параметра в другую' normal function' (B), но у меня нет способа сделать результат const. Решение состоит в том, чтобы включить промежуточную 'const-переменную', чтобы удерживать результат, а затем передавать' const-переменную' функцию B, что я не хочу – jayatubi

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 может быть оценена в время компиляции или во время выполнения, если он не используется в качестве постоянного выражения, и в этом случае она должна быть оценивается во время компиляции. Чтобы гарантировать оценку времени компиляции , мы должны либо использовать ее там, где требуется постоянное выражение (например, в качестве привязки массива или как метка case) или использовать его для инициализации constexpr. Я хотел бы надеяться, что ни один уважающий себя компилятор не упустит возможности оптимизации сделать то, что изначально сказал: «Функция constexpr оценивается во время компиляции, если все его аргументы являются постоянными выражениями».

+4

Это, однако, никогда не заставит компилятор жаловаться. Используя параметр constexpr в качестве шаблона, просто _forces_ компилятор оценивает его во время компиляции. Это, конечно, возможно, если функция соответствует строгим требованиям для 'constexpr' (иначе компилятор жалуется намного раньше). Тем не менее, он может по-прежнему оценивать одну и ту же функцию во время выполнения в другом месте (особенно gcc делает именно это! Вы подумали бы, что однажды-compiletime, компилятор достаточно умен, чтобы запомнить это для всех целей. Это не так.) – Damon

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; 
4

С НКОЙ, по крайней мере, вы можете получить значение constexpr быть вычислено во время компиляции, что делает его статическим переменным :

static const unsigned fibNUM = fib(NUM); 

Как я прочитал стандарт, он по-прежнему разрешено вычислять значение при запуске, но на практике это будет вычислено во время компиляции.

+0

это круто но почему бы не добавить всего 4 символа const-> constexpr и гарантировать все? – RiaD

+0

@RIAD: У вас есть стандартная цитата, которая подтверждает эту гарантию? – rici

Смежные вопросы