Question

I have defined a constexpr function as following:

constexpr int foo(int i)
{
    return i*2;
}

And this is what in the main function:

int main()
{
    int i = 2;
    cout << foo(i) << endl;
    int arr[foo(i)];
    for (int j = 0; j < foo(i); j++)
        arr[j] = j;
    for (int j = 0; j < foo(i); j++)
        cout << arr[j] << " ";
    cout << endl;
    return 0;
}

The program was compiled under OS X 10.8 with command clang++. I was surprised that the compiler did not produce any error message about foo(i) not being a constant expression, and the compiled program actually worked fine. Why?

Was it helpful?

Solution

The definition of constexpr functions in C++ is such that the function is guaranteed to be able to produce a constant expression when called such that only constant expressions are used in the evaluation. Whether the evaluation happens during compile-time or at run-time if the result isn't use in a constexpr isn't specified, though (see also this answer). When passing non-constant expressions to a constexpr you may not get a constant expression.

Your above code should, however, not compile because i is not a constant expression which is clearly used by foo() to produce a result and it is then used as an array dimension. It seems clang implements C-style variable length arrays as it produces the following warning for me:

warning: variable length arrays are a C99 feature [-Wvla-extension]

A better test to see if something is, indeed, a constant expression is to use it to initialize the value of a constexpr, e.g.:

constexpr int j = foo(i);

OTHER TIPS

I used the code at the top (with "using namespace std;" added in) and had no errors when compiling using "g++ -std=c++11 code.cc" (see below for a references that qualifies this code) Here is the code and output:

 #include <iostream>
 using namespace std;

 constexpr int foo(int i)
 {
    return i*2;
 }

 int main()
 {
   int i = 2;
   cout << foo(i) << endl;
   int arr[foo(i)];
   for (int j = 0; j < foo(i); j++)
      arr[j] = j;
   for (int j = 0; j < foo(i); j++)
      cout << arr[j] << " ";
   cout << endl;
   return 0;
}
output:
4
0 1 2 3 

Now consider reference https://msdn.microsoft.com/en-us/library/dn956974.aspx It states: "...A constexpr function is one whose return value can be computed at compile when consuming code requires it. A constexpr function must accept and return only literal types. When its arguments are constexpr values, and consuming code requires the return value at compile time, for example to initialize a constexpr variable or provide a non-type template argument, it produces a compile-time constant. When called with non-constexpr arguments, or when its value is not required at compile-time, it produces a value at run time like a regular function. (This dual behavior saves you from having to write constexpr and non-constexpr versions of the same function.)"
It gives as valid example:

   constexpr float exp(float x, int n)
   {
      return n == 0 ? 1 :
       n % 2 == 0 ? exp(x * x, n / 2) :
       exp(x * x, (n - 1) / 2) * x;
   }

This is an old question, but it's the first result on a google search for the VS error message "constexpr function return is non-constant". And while it doesn't help my situation, I thought I'd put my two cents in...

While Dietmar gives a good explanation of constexpr, and although the error should be caught straight away (as it is with the -pedantic flag) - this code looks like its suffering from some compiler optimization.

The value i is being set to 2, and for the duration of the program i never changes. The compiler probably noticed this and optimized the variable to be a constant (just replacing all references to variable i to the constant 2... before applying that parameter to the function), thus creating a constexpr call to foo().

I bet if you looked at the disassembly you'd see that calls to foo(i) were replaced with the constant value 4 - since that is the only possible return value for a call to this function during execution of the program.

Using the -pedantic flag forces the compiler to analyze the program from the strictest point of view (probably done before any optimizations) and thus catches the error.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top