Where does the C ++ 11 standard indicate when the constexpr function can be evaluated during translation?

Just because a function (or constructor) ...

  • declared constexpr and
  • function definition complies with constexpr requirements

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

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

Section 5.19 Paragraph 1 states that constant expressions can be evaluated at the time of translation. As far as I can understand, the rest of Section 5.19 outlines the rules for what is valid in the definition of the constexpr function.

I understand that I can make constexpr evaluate 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 have not been able to find paragraphs in FDIS that:

  • Force twoEulers to evaluate during translation or
  • Indicate other situations where the compiler may or should evaluate the constexpr function during translation.

What interests me especially is whether constexpr is triggered during translation:

  • When all parameters passed to constexpr are literals or
  • The implied argument of the object when resolving overload (section 13.3.1, paragraph 3) is either constexpr or requires a literal (for example, for array sizes) or
  • Something else completely.

Whenever possible, indicate in your answers sections of FDIS that I can find or key phrases that I can find in FDIS. English is somewhat dumb in the standard, so I may have read the relevant paragraphs and completely missed their point or intention.

+18
c ++ c ++ 11 constexpr
Nov 26 '12 at 19:30
source share
4 answers

When combing FDIS, I found three places that determine where the expression constexpr should be evaluated during translation.

Section 3.6.2 Initialization of non-local variables , paragraph 2 says that if an object with a static or local storage time of the stream is initialized by the constexpr constructor, then the constructor is evaluated during translation:

Continuous initialization is performed:

  • if an object with a statics or duration of the thread storage is initialized by a constructor call, if the constructor is a constexpr constructor, if all constructor arguments are constant expressions (including conversions), and if after replacing the function call (7.1) .5), each constructor call and the full expression in mem -initializers is a constant expression;

. Section 7.1.5. The constexpr specifier , clause 9 says that if an object declaration includes a constexpr , this object is evaluated during translation (i.e. it is a literal):

A constexpr qualifier used in declaring an object declares the object as const. Such an object must be of literal type and must be initialized. If it is initialized with a constructor call, this call must be a constant expression (5.19). Otherwise, each complete expression that appears in its initializer must be a constant expression. Each implicit conversion used in the conversion of initializer expressions and each constructor call used for initialization must be one of the allowed in the constant expression (5.19).

Ive heard people claim that this paragraph leaves room for implementation to delay initialization until runtime if the effect cannot be detected during translation due to, say, static_assert . This is probably not an accurate view, because, regardless of whether the value is initialized during translation, it is observable in some cases. This view is reinforced by Section 5.19 Permanent Expressions , paragraph 4:

[Note. Although in some contexts constant expressions must be evaluated during program translation, others may be evaluated during program execution. Since this international standard does not impose any restrictions on the accuracy of floating point operations, it is unclear whether evaluating a floating point expression during translation gives the result of the same result as evaluating the same expression (or the same operations with the same values) in program execution time ... - end note]

Section 9.4.2 Static data elements , paragraph 3 says that if a constant static data member of type literal is initialized by a constexpr function or constructor, then this function or constructor must be evaluated during translation:

If the static data member is of type const literal, its declaration in the class definition may indicate a logical or orthogonal initializer in which each initializer clause, which is an assignment expression, is a constant expression. The static literal data member can be declared in the class definition using the constexpr ; if so, his declaration specifies a logical or equal-initializer, in which each initializing clause, which is an assignment expression, is a constant expression. [Note. In both cases, the term can be displayed in constant expressions. - final note]

Interestingly, I did not find anything in FDIS, which required a constexpr expression to evaluate if its result was used as an array dimension. I am quite sure that the standard committee expects this to happen. But I could also skip this in my quest.

Outside of these conditions, the C ++ 11 standard allows calculations in design functions and constructors during translation. But that does not require it. Calculations may occur at run time. What kind of calculations that the compiler performs during translation is to a certain extent a matter of implementation quality.

In all three situations that I discovered, the trigger for estimating the translation time is based on the requirements of the target, using the result of calling constexpr . Regardless of whether constexpr function arguments are literals, they are never considered (although this is a prerequisite for a correct evaluation).

So, in order to get to the real point, it seems that the constexpr evaluation during the translation is started with:

  • The implied argument of the object when resolving overload (section 13.3.1, paragraph 3) is either constexpr or requires a literal.

I hope this helps someone other than me. Thanks to everyone who contributed.

+4
Dec 09
source share

It is "allowed" to evaluate the call to constexpr at compile time, when it is really possible. Remember that the specification works according to the “as if” rule. Therefore, if you cannot tell the difference, the compiler can do whatever it wants.

The compiler should evaluate constexpr calls at compile time, when it really needs a response at compile time. For example:

 constexpr int foo() {return 5;} std::array<float, foo()> arr; 

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

+6
Nov 27 '12 at 6:18
source share

Nicole Bolas is 100% right, but there is another interesting aspect: whether the expression is evaluated during translation and whether it is evaluated at runtime, are completely independent questions. Since a constant expression cannot have side effects, it can be evaluated an arbitrary number of times, and nothing prevents it from being evaluated both during translation and during execution.

Suppose a constant expression is a large array (not std::array , just an array), which is completely legal, and the program does not indicate that it has static storage. Assume also that in the context in which compilation time calculation is required, only array element 7 is used. It is quite reasonable for the compiler to compute the entire array, use element 7, drop it and paste the code to compute it at run time in the area in which it is used, instead of inflating the binary file with the entire computable array. I believe this is not a theoretical question; I have observed this with various compilers in different contexts. constexpr does not mean static .

Of course, if the compiler can determine that the array is not used at run time, it may not even embed code to compute it, but this is another problem.

If you use such an object at runtime, and you want to tell the compiler that it should be supported throughout the program, you must declare it as static .

+4
Nov 27 '12 at 6:41
source share

I do not think it was anywhere. I also had a look, it is difficult, because there is no single article on constexpr in this list; they all seem to add / remove from the previous collection of articles.

I think the general idea is that the inputs to constexpr functions are themselves, all this will be done at compile time; and to extend non-functional constexpr statements, which are literal in any case, will be executed at compile time if you use a semi-small intelligent compiler.

If a constexpr function or constructor is called with arguments that are not constant expressions, the call behaves as if the function was not constexpr, and the resulting value is not a constant expression.

from wikipedia

which appears to be getting information from this pdf :

constexpr functions: the constexpr function is a function that is "suf-simple enough" to provide a constant expression when called with arguments that are constant values ​​(see section 2.1).

+1
Nov 27
source share



All Articles