Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where in the C++11 standard does it specify when a constexpr function can be evaluated during translation?

Just because a function (or constructor)...

  • is declared constexpr and
  • the function definition meets the constexpr requirements

...doesn't mean that the compiler will evaluate the constexpr function during translation. I've been looking through the C++11 FDIS (N3242, available at http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/) to try and determine two things:

  • When is the compiler obligated to evaluate a constexpr function during translation?
  • When is the compiler allowed to evaluate a constexpr function during translation?

Section 5.19 Paragraph 1 says that constant expressions can be evaluated during translation. As far as I can comprehend, the remainder of Section 5.19 sets forth the rules for what is valid in the definition of a constexpr function.

I understand that I can force constexpr evaluation during translation by declaring the result of the constexpr function as constexpr. Like this:

// Declaration
constexpr double eulers_num() { return 2.718281828459045235360287471; }

// Forced evaluation during translation
constexpr double twoEulers = eulers_num() * 2.0;
static_assert(twoEulers > 5.0, "Yipes!");

So far I've been unable to find the paragraphs in the FDIS that:

  • Force twoEulers to be evaluated during translation or
  • Specify other situations when the compiler may or must evaluate a constexpr function during translation.

What I'm particularly interested in discovering is whether constexpr evaluation during translation is triggered by:

  1. When all parameters passed to the constexpr function are literals, or
  2. The implied object argument during overload resolution (Section 13.3.1 Paragraph 3) is either constexpr or requires a literal (such as for array dimensions), or
  3. Something else entirely.

Please, if possible, in your responses cite sections of the FDIS that I can look up or key phrases I can search in the FDIS. The English in the standard is somewhat obtuse, so I may have been reading the relevant paragraphs and have entirely missed their meaning or intent.

like image 757
sschurr Avatar asked Nov 26 '12 19:11

sschurr


People also ask

When can a function be constexpr?

A constexpr function is one whose return value is computable at compile time when consuming code requires it. Consuming code requires the return value at compile time to initialize a constexpr variable, or to provide a non-type template argument.

Is constexpr evaluated at compile time?

A constexpr function that is eligible to be evaluated at compile-time will only be evaluated at compile-time if the return value is used where a constant expression is required. Otherwise, compile-time evaluation is not guaranteed.

Does C have constexpr?

No, no such thing exists in C.

When to use #define vs constexpr?

#define (also called a 'macro') is simply a text substitution that happens during preprocessor phase, before the actual compiler. And it is obviously not typed. constexpr on the other hand, happens during actual parsing. And it is indeed typed.


2 Answers

It is "allowed" to evaluate the constexpr call at compile time whenever it is actually possible to do so. Remember that the specification operates under the "as if" rule. So if you can't tell the difference, the compiler can do whatever it wants.

The compiler is required to evaluate constexpr calls at compile time when it actually needs the answer at compile time. For example:

constexpr int foo() {return 5;}

std::array<float, foo()> arr;

The compiler needs to know the array size at compile time. Therefore, it must evaluate the constant expression at compile time. If the constexpr function cannot be executed at compile time, you get a compile-time error.

like image 53
Nicol Bolas Avatar answered Oct 14 '22 00:10

Nicol Bolas


Nicol Bolas is 100% correct, but there is one other interesting aspect: whether the expression is evaluated at translation-time and whether it is evaluated at run-time are completely independent questions. Since the constant expression cannot have side-effects, it can be evaluated an arbitrary number of times, and nothing stops it from being evaluated at both translation-time and run-time.

Suppose the constant expression were a large array (not a std::array, just an array), which is entirely legal, and the program does not indicate that it has static storage. Suppose also that only element 7 of the array is used in a context in which compile-time computation is necessary. It is quite reasonable for the compiler to compute the entire array, use element 7, discard it, and insert code to compute it at run-time in the scope in which it is used, rather than bloating the binary with the whole computed array. I believe this is not a theoretical issue; I've observed it with various compilers in various contexts. constexpr does not imply static.

Of course, if the compiler can determine that the array is not used at runtime, it might not even insert code to compute it, but that's yet another issue.

If you do use such an object at run-time, and you want to indicate to the compiler that it would be worth keeping it around for the duration of the program, you should declare it as static.

like image 20
rici Avatar answered Oct 14 '22 00:10

rici