Why is C ++ 11 constexpr so restrictive?

As you probably know, C ++ 11 represents the constexpr keyword.

C ++ 11 introduces the constexpr keyword, which allows the user to ensure that the constructor of a function or object is a constant compilation time. [...] This allows the compiler to understand and verify that [function name] is a compile-time constant.

My question is: why are there such strict restrictions on the form of functions that can be declared. I understand the desire to ensure that the function is clean, but consider the following:

Using constexpr for a function imposes some limitations on what this function can do. First, the function must have a non-empty return type. Secondly, the body of a function cannot declare variables or define new types. Third, the body can only contain declarations, null statements, and one return statement. Argument values ​​must exist, such that after replacing the argument, the expression in the return statement expresses a constant expression.

This means that this pure function is illegal:

 constexpr int maybeInCppC1Y(int a, int b) { if (a>0) return a+b; else return ab; //can be written as return (a>0) ? (a+b):(ab); but that isnt the point } 

Also you cannot define local variables ... :( So I wonder if this is a design decision, or do compilers suck when it comes to proving function a, is it clean?

+51
c ++ c ++ 11 constexpr
Nov 29 '11 at 9:55
source share
5 answers

The reason you need to write statements instead of expressions is because you want to use the extra capabilities of statements, in particular the ability to loop. But to be useful, this would require the ability to declare variables (also forbidden).

If you combine a looping tool with mutable variables, with logical forking (as in the if ), then you have the ability to create infinite loops. It is not possible to determine whether such a cycle will end ( problem with stopping ). Thus, some sources may cause the compiler to freeze.

Using recursive pure functions, you can invoke infinite recursion, which can be shown equivalent to the powerful looping capabilities described above. However, C ++ already has this problem during compilation — this happens with a template extension — and therefore compilers should already have a switch for the “depth of the template stack” so that they know when to refuse.

Thus, the constraints are apparently intended to ensure that this problem (determining when the C ++ compilation will ever end) is not more complicated than it is.

+29
Nov 29 '11 at 10:20
source share

The rules for constexpr functions constexpr designed in such a way that it is impossible to write a constexpr function that has any side effects.

If constexpr is required to have no side effects, the user cannot determine where / when it was actually evaluated. This is important because constexpr functions constexpr allowed both at compile time and at run time at the discretion of the compiler.

If side effects were resolved, then there should be some rules about the order in which they will be observed. That would be incredibly hard to define - even harder than the static initialization order issue.

A relatively simple set of rules guaranteeing free access to these functions should require that they be just one expression (with some additional restrictions on this). This sounds limited at first, and as you noted, excludes the if statement. Although there would be no side effects in this particular case, it would introduce additional complexity into the rules and provided that you can write the same things with the ternary operator or recursively this is not a big deal.

n2235 is an article that suggested the addition of constexpr in C ++. It discusses the rational for design - the corresponding quote seems to be from the discussion of destructors, but in general it matters:

The reason is that the constant expression is intended to be evaluated by the compiler during translation, like any other literal of a built-in type; in particular, no observable side effect is allowed.

Interestingly, the document also mentions that in the previous sentence it was assumed that the compiler automatically figured out what functions were constexpr without a new keyword, but this turned out to be inoperative, which seems to confirm my assumption that the rules were designed to be simple.

(I suspect there will be other citations in the links cited in the article, but this is about the key point of my side effect argument)

+25
Nov 29 '11 at 3:26 a.m.
source share

In fact, the C ++ Standardization Committee is thinking about removing some of these restrictions for C ++ 14. See the following working document http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013 /n3597.html

+12
Jul 17 '13 at 21:28
source share

Restrictions, of course, can be canceled quite a bit, without including code that cannot be executed at compile time or that cannot be proved to always stop. However, I think this was not done because

  • this will complicate the compiler for minimal gain. C ++ compilers are pretty complicated, like

  • an accurate determination of how much is allowed without violating the above restrictions would take a lot of time and given that the desired functions were delayed to get the standard outside the home, there was probably little incentive to add more work (and further delay in the standard) for a small gain .

  • some of the restrictions would be either quite arbitrary or rather complex (especially in loops, given that C ++ does not have the concept of its own increment for a loop, but both the final condition and the increment code have to be explicitly specified in the for statement, which allows use arbitrary expressions for them)

Of course, only a member of the standards committee can give an authoritative answer whether my assumptions are correctly made.

+3
Nov 29 '11 at 19:24
source share

I think constexpr is only for const objects. I mean; Now you can statically create const objects, such as String::empty_string , statically (without hacking!). This can shorten the time before calling "main". And static const objects can have functions such as .length(), operator==,... , so "expr" is therefore required. In 'C' you can create static constant structures, as shown below:

 static const Foos foo = { .a = 1, .b = 2, }; 

There are tons of classes of this type in the Linux kernel. In C ++, you can do it now with constexpr.

note: I do not know, but the code below should not be accepted as if the version were:

 constexpr int maybeInCppC1Y(int a, int b) { return (a > 0) ? (a + b) : (a - b); } 
-four
Feb 01 '13 at 8:37
source share



All Articles