3

Ok, this might be a stupid question, but I completely don't understand chapter 12.1.6.2 - conditional evaluation under constexpr functions of the c++ programming language. This is the whole very short text.

A branch of a conditional expression that is not taken in a constexpr function is not evaluated. This implies that a branch not taken can require run-time evaluation. For example:

constexpr int check(int i)
{
    return (low<=i && i<high) ? i : throw out_of_range();
}

constexpr int low = 0;
constexpr int high = 99;

// ...
constexpr int val = check(f(x,y,z));

You might imagine low and high to be configuration parameters that are known at compile time, but not at design time, and that f(x,y,z) computes some implementation-dependent value.

Source for context

I tried running the code above to try to more understand the explanation but I'm getting an error. Can someone provide a clearer explanation?

Edit: I created a program to test this:

#include<iostream>
#include<stdexcept>

using namespace std;

constexpr int low = 0;
constexpr int high = 99;

constexpr int check(int i) {
    return (low<=i && i<high) ? i : throw out_of_range();
}

constexpr int f(int x, int y, int z) {
    return x*y*z;
}

int main() {
    constexpr int val = check(f(2,2,2));
    cout << val << '\n';
}

It won't run:

no matching function for call to 'std::out_of_range::out_of_range()' //I'm really surprised at this
     return (low<=i && i<high) ? i : throw out_of_range();
error: body of constexpr function 'constexpr int check(int)' not a return-statement
 }
error: 'constexpr int check(int)' called in a constant expression
  constexpr int val = check(f(2,2,2));
lightning_missile
  • 2,821
  • 5
  • 30
  • 58
  • 1
    Note `f` must also be a `constexpr` function. – aschepler Sep 30 '14 at 16:20
  • You might want to see if `static_assert()` can be of use. http://en.cppreference.com/w/cpp/language/static_assert – dgnuff Sep 30 '14 at 16:43
  • @dgnuff `static_assert` _requires_ a constant expression, so if you added it to `check` you could not call `check` at run-time with non-constant arguments. The point of the example above is that it is a valid run-time check, that can also be used to initialize constexpr variables. – Jonathan Wakely Sep 30 '14 at 17:02

1 Answers1

8

It means that a conditional branch in a constexpr function is allowed to use non-constant expressions (i.e. ones requiring run-time evaluation, such as throwing exceptions) as long as that branch is never taken when the function is called in a constant expression context.

So it's OK to call check to initialized the constexpr variable val, as long as the arguments to the function are constant expressions, and the condition (low<=i && i<high) is true.

If the arguments are not constants, the function call is not a constant expression and so can't initialize a constexpr variable.

If the condition is false the function needs to take the false branch, which needs to throw an exception, which requires run-time evaluation, so the function is not a constant expression, and so cannot initialize a constexpr variable.

When the argument is a constant expression, the compiler knows at compile-time whether the branch will be taken, so as long as the condition is true it can completely ignore the false branch, and doesn't complain that throwing exceptions is impossible at compile-time.

When the function is called at run-time, it can have any arguments, and the false branch can be taken and the throw will be evaluated as for a normal (non-constexpr) function.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521