C++ full-expression standard wording - c++

In paragraph 12 of [intro.execution] in the current (C++ 17) C++ standard draft there is written:
A full-expression is:
[...]
an expression that is not a subexpression of another expression and that is not otherwise part of a full-expression.
If a language construct is defined to produce an implicit call of a function, a use of the language construct is considered to be an expression for the purposes of this definition. [...]
The "use of the language construct" wording refers to the fact that the construct itself is to be considered an expression or the implicit calls that the construct "uses" are to be considered as expressions?
I am asking this because in the same paragraph there is this code sample:
S s1(1); // full-expression is call of S​::​S(int)
The comment would indicate that the second interpretation is correct.
However, the paragraph explicitly says that an init-declarator is a full-expression, which would indicate that the comment is wrong.
In the past (I believe even before C++03), this paragraph looked like this (taken from this defect report):
A full-expression is an expression that is not a subexpression of another expression. If a language construct is defined to produce an implicit call of a function, a use of the language construct is considered to be an expression for the purposes of this definition.
[Note: certain contexts in C++ cause the evaluation of a full-expression that results from a syntactic construct other than expression (5.19 [expr.comma]). For example, in 8.6 [dcl.init] one syntax for initializer is
( expression-list )
but the resulting construct is a function call upon a constructor function with expression-list as an argument list; such a function call is a full-expression. For example, in 8.6 [dcl.init], another syntax for initializer is
= initializer-clause
but again the resulting construct might be a function call upon a constructor function with one assignment-expression as an argument; again, the function call is a full-expression. ]
This is another reason for believing that the second interpretation is the one intended.
I know that it makes no difference to the understanding of the language, but I just want to know what was the intention of the person who initially wrote that paragraph.

Related

"full-expression" versus "full expression"

I was looking at this post in GitHub, but I couldn't understand what the OP meant by this:
"full expression" suggest that it is a kind of expression, but sometimes it is not.
My interpretation is that a "full-expression" (term used in the Standard) may not be an expression. [intro.execution]/5 gives the definition for full-expression, as follows:
A full-expression is
(5.1) — an unevaluated operand (8.2),
(5.2)
— a constant-expression (8.6),
(5.3) — an init-declarator (Clause
11) or a mem-initializer (15.6.2), including the constituent
expressions of the initializer,
(5.4) — an invocation of a
destructor generated at the end of the lifetime of an object other
than a temporary object (15.2), or
(5.5) — an expression that is not
a subexpression of another expression and that is not otherwise part
of a full-expression.
If my interpretation is correct I would like to know which of the bullet points above yields a full-expression that is not an expression. Otherwise, i.e., if I'm wrong, what did the OP mean by his comment?
The formal list of expressions can be found in [gram.expr]. It is quite a bit of text so I am not going to include it here but using it we can see that an init-declarator and a mem-initializer are not expressions according to the grammar. That means even though an init-declarator and a mem-initializer are considered full expressions, grammatically they are not expressions.

Why are lambda expressions not allowed in an unevaluated operands but allowed in the unevaluated portions of constant expressions?

If we look at the draft C++ standard section 5.1.2 Lambda expressions paragraph 2 says (emphasis mine going forward):
The evaluation of a lambda-expression results in a prvalue temporary (12.2). This temporary is called the closure object. A lambda-expression shall not appear in an unevaluated operand (Clause 5). [ Note: A closure object behaves like a function object (20.8).—end note ]
and section 5.19 Constant expressions paragraph 2 says:
A conditional-expression is a core constant expression unless it involves one of the following as a potentially evaluated subexpression (3.2), but subexpressions of logical AND (5.14), logical OR (5.15), and conditional (5.16) operations that are not evaluated are not considered [...]
and has the following bullet:
— a lambda-expression (5.1.2);
So why are lambdas expressions not allowed in an unevaluated operand but are allowed in the unevaluated portions of constant expressions?
I can see how for unevaluated operands the type information in several cases(decltype or typeid) is not very useful since each lambda has a unique type. Although why we would want to allow them in the unevaluated context of a constant expression is not clear, perhaps to allow for SFINAE?
The core reason for the unevaluated operands exclusion is covered in C++ Standard Core Language Defect Reports and Accepted Issues #1607. Lambdas in template parameters which seeks to clarify this restriction and states the intention of the restriction in section 5.1.2 was to:
[...] avert the need to deal with them in function template signatures [...]
As the issue documents the current wording actually has a hole since constant expressions allows them in an unevaluated context. But it does not outright state the rationale for this restriction. The desire to avoid name mangling stands out and you can infer that avoiding extending SFINAE was also desired since the proposed resolution seeks to tighten the restriction even though several viable alternatives would have allowed SFINAE. The modified version of 5.1.2 paragraph 2 as follows:
A lambda-expression shall not appear in an unevaluated operand (Clause 5 [expr]), in a template-argument, in an alias-declaration, in a typedef declaration, or in the declaration of a function or function template outside its function body and default arguments [Note: The intention is to prevent lambdas from appearing in a signature —end note]. [Note: A closure object behaves like a function object (20.10 [function.objects]). —end note]
This proposal was accepted and is in N3936(see this answer for a link)
For a more explicit discussion of the rationale to avoid having lambdas as an unevaluated operand. The discussion titled Rationale for lambda-expressions not being allowed in unevaluated contexts on comp.lang.cpp.moderated Daniel Krügler lays out three reasons:
The extreme extension of possible SFINAE cases :
[...]The reason why they became excluded was due to exactly this extreme extension of sfinae cases (you were opening a Pandora box for the compiler)[...]
In many cases it is just useless since each lambda has a unique type, the hypothetical example given:
template<typename T, typename U>
void g(T, U, decltype([](T x, T y) { return x + y; }) func);
g(1, 2, [](int x, int y) { return x + y; });
The type of the lambda in the declaration and the call are different(by definition) and therefore this can not work.
Name mangling also becomes a problem since once you allow a lambda in a function signature the bodies of the lambda will have to be mangled as well. This means coming up with rules to mangle every possible statement, which would burdensome for at least some implementations.

C++14: can you call new in a constexpr?

When C++14 lifted restrictions on constexpr it seemed to include the following (copied from Wikipedia):
Expressions may change the value of an object if the lifetime of that
object began within the constant expression function. This includes
calls to any non-const constexpr-declared non-static member functions.
That seems to imply that you could create an object using new and as long as you delete it within the expression, then it would be allowed.
Language lawyer answer. All references to N3797.
7.1.5/5 states:
For a non-template, non-defaulted constexpr function or a non-template, non-defaulted, non-inheriting constexpr constructor, if no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression (5.19), the program is ill-formed; no diagnostic required.
Jumping over to 5.19, we see:
A conditional-expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine (1.9), would evaluate one of the following expressions:
... [lots of bullets]...
a new-expression (5.3.4);
a delete-expression (5.3.5);
... [lots more bullets]...
So no: a program containing a constexpr function with an unconditional invocation of new or delete in it is ill-formed, no diagnostic required. (I'd be surprised, however, if any half-decent compiler failed to diagnose such invocations of new or delete in a constexpr function, required or not.)
I don't think so. You are still limited to calling other constexpr functions. new is actually a function call to operator new() which is not a constexpr function. The same goes for delete.

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:
When all parameters passed to the constexpr function are literals, or
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
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.
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.
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.
By combing the FDIS I have found three places that specify where a constexpr expression must be evaluated during translation.
Section 3.6.2 Initialization of non-local variables, paragraph 2 says if an object with static or thread local storage duration is initialized with a constexpr constructor then the constructor is evaluated during translation:
Constant initialization is performed:
if an object with static or thread storage duration 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 function invocation substitution (7.1.5), every constructor call and full-expression in the mem-initializers is a constant expression;
Section 7.1.5 The constexpr specifier, paragraph 9 says if an object declaration includes the constexpr specifier, that object is evaluated during translation (i.e., is a literal):
A constexpr specifier used in an object declaration declares the object as const. Such an object shall have literal type and shall be initialized. If it is initialized by a constructor call, that call shall be a constant expression (5.19). Otherwise, every full-expression that appears in its initializer shall be a constant expression. Each implicit conversion used in converting the initializer expressions and each constructor call used for the initialization shall be one of those allowed in a constant expression (5.19).
I’ve heard people argue that this paragraph leaves room for an implementation to postpone the initialization until runtime unless the effect can be detected during translation due to, say, a static_assert. That is probably not an accurate view because whether a value is initialized during translation is, under some circumstances, observable. This view is reinforced by Section 5.19 Constant 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 imposes no restrictions on the accuracy of floating-point operations, it is unspecified whether the evaluation of a floating-point expression during translation yields the same result as the evaluation of the same expression (or the same operations on the same values) during program execution... — end note ]
Section 9.4.2 Static data members, paragraph 3 says if a const static data member of literal type is initialized by a constexpr function or constructor, then that function or constructor must be evaluated during translation:
If a static data member is of const literal type, its declaration in the class definition can specify a brace-orequal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. A static data member of literal type can be declared in the class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. [ Note: In both these cases, the member may appear in constant expressions. — end note ]
Interestingly, I did not find anything in the FDIS that required a constexpr expression to be evaluated if its result is used as an array dimension. I'm quite sure the standard committee expects that to be the case. But I also could have missed that in my search.
Outside of those circumstances the C++11 standard allows computations in constexpr functions and constructors to be performed during translation. But it does not require it. The computations could occur at runtime. Which computations the compiler performs during translation are, to a certain extent, a quality of implementation question.
In all three of the situations I located, the trigger for translation-time evaluation is based on the requirements of the target using the result of the constexpr call. Whether or not the arguments to the constexpr function are literal is never considered (although it is a pre-requisite for valid evaluation).
So, to get to the real point of this, it appears that constexpr evaluation during translation is triggered by:
The implied object argument during overload resolution (Section 13.3.1 Paragraph 3) is either constexpr or requires a literal.
I hope that's helpful to someone besides me. Thanks to everyone who contributed.
I don't think it's forced anywhere. I had a look too, it's tricky because there's not one paper on constexpr in that list; they all seem to add/remove from the previous collection of papers.
I think the general idea is when the inputs to the constexpr function are constexpr themselves, it'll all be done at compile time; and by extension non-function constexpr statements, which are literal anyway will be run at compile time if you're using a half intelligent compiler.
If a constexpr function or constructor is called with arguments which
aren't constant expressions, the call behaves as if the function were
not constexpr, and the resulting value is not a constant expression.
from wikipedia
which in seem to get the info from this pdf:
constexpr functions: A constexpr function is one which is “suf-
ficiently simple” so that it delivers a constant expression when
called with arguments that are constant values (see §2.1).

Can anyone explain this paragraph of the current C++0x standard draft?

Can anyone explain this statement from ISO N3242 §3.2, 2nd point
An expression is potentially evaluated unless it is an unevaluated operand
(Clause 5) or a subexpression thereof. A variable or non-overloaded
function whose name appears as a potentially-evaluated expression is
odr-used unless it is an object that satisfies the requirements for appearing in a
constant
expression (5.19) and the lvalue-to-rvalue conversion (4.1) is
immediately
applied. this is odr-used if it appears as a potentiallyevaluated
expression
(including as the result of the implicit transformation in the body of
a
non-static member function (9.3.1)).
ISO Standard 2003 : says
An expression is potentially evaluated unless it appears where an
integral
constant expression is required (see 5.19), is the operand of the
sizeof
operator (5.3.3), or is the operand of the typeid operator and the
expression
does not designate an lvalue of polymorphic class type (5.2.8). An
object or
non-overloaded function is used if its name appears in a
potentially-evaluated
expression.
What is the actual difference in these statements?
Can any one explain this with the help of an example/program?
"unevaluated operand" replaces "is the operand of the sizeof operator (5.3.3), or is the operand of the typeid operator and the expression does not designate an lvalue of polymorphic class type (5.2.8)". It has the same basic purpose, but doesn't try to list all the cases in the C++0x standard of operators whose operands aren't evaluated. decltype is a new one, for example.
"odr-used" replaces "used", I presume they figured that "used" alone might be ambiguous with other uses of the word "use" in the standard. In both cases, though, it's defining the sense of "used" which is relevant to the ODR.
So those aren't really changes, just re-wordings updated for C++0x.
This is a change:
A variable or non-overloaded function
whose name appears as a
potentially-evaluated expression is
odr-used unless it is an object
that satisfies the requirements for
appearing in a constant expression
(5.19) and the lvalue-to-rvalue
conversion (4.1) is immediately
applied.
vs.
An object or non-overloaded
function is used if its name appears
in a potentially-evaluated
expression.
Suppose a is a static const int at global scope. Then in C++03 it is not used in the following statement:
char x[a];
because the context requires a constant expression. However, it is used in the following:
void foo(int); foo(a);
because the context doesn't require a constant expression.
In C++0x, a is not odr-used in either case. It's allowed to be in a constant expression, and in the function call, lvalue-rvalue conversion is immediately applied (because foo takes its parameter by value, not reference). So it qualifies for the "unless" which wasn't present in C++03.
There's also a difference in the definition of "potentially evaluated". In the first example, char x[a], a is potentially evaluated in C++03 but not in C++0x. I haven't checked whether anything else in the standard uses "potentially evaluated", that might be affected by this change. If it's only mentioned here then that part of it isn't a change, it's just that the exception has been moved from "potentially evaluated" to "used".