6

I want to compare meta programming and use of constexpr in c++0x. then I write a fib function in both model. when I use meta programming model, answer print out very fast because it calculated in compile time. but when I use constexpr funcion it calculate value in run time, not in compile time. I using g++( gcc ) 4.8 .can any body help me?

#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;
}
mostafa88
  • 532
  • 1
  • 8
  • 20
  • [Both look compile-time to me.](http://coliru.stacked-crooked.com/a/5fe7e66ca805e846) – chris Dec 19 '13 at 13:28
  • Isn't the idea of constexpr is that it works in compile time? – Kakalokia Dec 19 '13 at 13:29
  • 8
    How do you know it calculates the value at runtime? Have you looked at the assembly? – juanchopanza Dec 19 '13 at 13:29
  • 2
    @juanchopanza: Compiling with gcc, its evaluated at runtime. Although you can simply force compile time evaluation with `constexpr unsigned i = fib(NUM);`. – Jesse Good Dec 19 '13 at 13:42
  • 1
    @juanchopanza: You just have to run it. You can see the cycles spinning before it prints the output. :) – rici Dec 19 '13 at 13:49
  • 1
    @juanchopanza: just a simple way ;) when i run this code, meta programming model answer fast , but constexpr model answer very slow. – mostafa88 Dec 19 '13 at 13:54

4 Answers4

9

I believe the reason is that constexpr is not guaranteed to execute at compile-time. To enforce compile-time evaluation, you have to assign it to a compile-time alias. Like,

enum {i = fib(NUM)};

Sergei Nosov
  • 1,637
  • 11
  • 9
  • Any way to make it be force evaluated even not to assign to a const variable? – jayatubi May 22 '15 at 14:45
  • Not sure I understood the question correctly. Are you asking for another way to guarantee compile-time evaluation besides using it in a 'const context'? The answer to this question is, probably, 'No'. – Sergei Nosov May 22 '15 at 15:22
  • For example I want to pass the result of a `constexpr function`(A) as a parameter to another `normal function`(B) but I have no way to make the result const. A solution is to involve an intermediate `const variable` to hold the result and then pass the `const variable` to function B which is what I don't want – jayatubi May 22 '15 at 15:31
  • Well, I don't think there's a better way to do that, if you have to absolutely guarantee compile-time evaluation. – Sergei Nosov May 22 '15 at 15:34
4

With gcc, at least, you can get the constexpr value to be computed at compile time by making it a static variable:

static const unsigned fibNUM = fib(NUM);

As I read the standard, it's still allowed to compute the value at startup, but in practice it will be computed at compile time.

rici
  • 234,347
  • 28
  • 237
  • 341
1

A simple test to see if your constexpr are really being done at compile-time is to use an std::array:

#include <array>

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

gcc has no complaints.

See this comment by Bjarne Stroustrup:

... according to the standard a constexpr function may be evaluated at compiler time or run time unless it is used as a constant expression, in which case it must be evaluated at compile-time. To guarantee compile-time evaluation, we must either use it where a constant expression is required (e.g., as an array bound or as a case label) or use it to initialize a constexpr. I would hope that no self-respecting compiler would miss the optimization opportunity to do what I originally said: "A constexpr function is evaluated at compile time if all its arguments are constant expressions."

  • 4
    That, however, will never cause the compiler to complain. Using a constexpr as template parameter simply _forces_ the compiler to evaluate it at compile-time. Which is of course possible if the function meets the strict requirements for `constexpr` (otherwise the compiler complains much earlier anyway). It may, however, still evaluate the same function at runtime in a different location (notably gcc does just that! You would think that once-compiletime, the compiler is smart enough to remember this for all uses. It's not.) – Damon Dec 19 '13 at 13:44
1

constexpr is not guaranteed to be evaluated at compile time. This means, compiler can choose whether to evaluate at compile time or at run time. You can try to assign it to a compile time constant and check like this...

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;