3
constexpr int func(int rf){
    constexpr int  v = rf;  // #1
    return 0;
}
int main(){
}

Consider the above code, the compiler complains such a code is ill-formed. The outcome is here:

error: 'rf' is not a constant expression

That is said, the expression at the place that marked with #1 is evaluated by the compiler. I agree that rf is not a constant expression, because it does violate the following rules:

An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine, would evaluate one of the following expressions:
expr.const#2

an lvalue-to-rvalue conversion unless it is applied to

  • a non-volatile glvalue of integral or enumeration type that refers to a complete non-volatile const object with a preceding initialization, initialized with a constant expression, or
  • a non-volatile glvalue that refers to a subobject of a string literal, or
  • a non-volatile glvalue that refers to a non-volatile object defined with constexpr, or that refers to a non-mutable subobject of such an object, or
  • a non-volatile glvalue of literal type that refers to a non-volatile object whose lifetime began within the evaluation of e;

However, what makes me confused is, I didn't call function func anywhere in my example, why the compiler evaluate the expression rf? That makes me don't understand what is evaluation and what is the execution.

According to this rule:
intro.execution#18

When calling a function (whether or not the function is inline), every value computation and side effect associated with any argument expression, or with the postfix expression designating the called function, is sequenced before execution of every expression or statement in the body of the called function. For each function invocation F, for every evaluation A that occurs within F and every evaluation B that does not occur within F but is evaluated on the same thread and as part of the same signal handler (if any), either A is sequenced before B or B is sequenced before A.

It sounds like that, only if the corresponding function is called, then the evaluation for expression which is in the function body does occur.

However, Obviously I didn't call func in my example. So, my questions are:

Question 1:

what situation will the evaluation for expressions occur in?
For constant expressions, there is only a crude tip in the standard, that is, [Note: Constant expressions can be evaluated during translation. — end note], there's no more.

Question 2:

As a contrast, If the statement at #1 would be int v = rf;, Does the compiler evaluate such an expression rf during translation if I don't call function func?

Question 3:

what's the difference between evaluation and execution?

Question 4:

where's the relevant clause in the standard specified what situation the evaluation for expressions will occur in?

xmh0511
  • 7,010
  • 1
  • 9
  • 36
  • Does this answer your question? [Where in C++14 Standard does it say that a non-constexpr function cannot be used in a definition of a constexpr function?](https://stackoverflow.com/questions/34272899/where-in-c14-standard-does-it-say-that-a-non-constexpr-function-cannot-be-used) – Language Lawyer Aug 28 '20 at 06:35
  • @LanguageLawyer It does not. – xmh0511 Aug 28 '20 at 06:38
  • @nop666 `At parsing time, it just consider the expression is ill-formed `, that is the question itselft. If `rf` is not evaluated by so-called **abstract machine**, how could the `machine` know whether `rf` is a constant expression or not? Since the compiler complains `rf` is not a constant expression, that is said, `rf` is evaluated to determine whether it is or not. – xmh0511 Aug 28 '20 at 06:50
  • @jackX From what I understand, the reasoning is "as I can't tell in this context, I consider it's not"... – nop666 Aug 28 '20 at 06:53
  • @nop666 what my supposition is that, the **abstract machine** evaluates every `expressions` which are required to be a constant expression at compile time, regardless of whether such entity would be executed at run time. However there's no relevant clause in [abstract machine](https://timsong-cpp.github.io/cppwp/n4659/intro.execution). – xmh0511 Aug 28 '20 at 07:01
  • The constexpr specifier declares that it is possible to evaluate the value of the function or variable at compile time. Such variables and functions can then be used where only compile time constant expressions are allowed. – Arjun U S Aug 28 '20 at 07:41
  • @jackX Just to clarify my supposition. At parsing time, it sees the `constexpr` expression inside `func`. As it is `constexpr`, it want to evaluate it (at the difference of a regular expression where it assesses it is well-formed). At this point, it cannot evaluate it as a `constexpr` becaue `rf` is not a const expression. – nop666 Aug 28 '20 at 08:57
  • @nop666 After thinking the question a long time, I think that all expressions need to be evaluated at compile time, the only distinction is that what conditions such an expression shall satisfy. At the point `#1`, `rf` needs eligible to be a constant expression. – xmh0511 Aug 28 '20 at 09:31

2 Answers2

0

the error comes from

    constexpr int  v = rf;  // #1

you are trying to make a constexpr equal to something that is not. The constexpr is evaluated at compile time but rf is calculated only at run time. That means that the compiler will try to make v equal to something that was not calculated yet.

gibs
  • 90
  • 6
  • I know `constexpr int v = rf;` is not a constant expression. However, to determine whether such expression `e` is a constant expression or not, it should be evaluated. The key point is, I don't call function `func`. why `rf` is evaluated? – xmh0511 Aug 28 '20 at 06:41
  • @jackX _why rf is evaluated?_ It is not. – Language Lawyer Aug 28 '20 at 06:41
  • @LanguageLawyer If `rf` is not evaluated, how does the abstract machine know whether `rf` is a constant expression or not per [expr.const]? – xmh0511 Aug 28 '20 at 06:44
  • 1
    I thought that is the point: everything with constexpr in front is evaluated (you will see at run time if it is used or not). rf is not constexpr and is not evaluated so you get an error because you can't initialize v. – gibs Aug 28 '20 at 06:46
  • @gibs I think not only these expressions with `constexpr` but also all expressions(at compile time), the only distinction is that what conditions such an expression shall satisfy when evaluating it. – xmh0511 Aug 28 '20 at 09:37
  • @LanguageLawyer - _"why `rf` is evaluated? It is not."_ This seems incorrect because how It's known that `rf` is not a core constant expression without evaluating it? Indeed the function has not even called but that does have nothing to do with constant evaluation (compile-time evaluation). – mada Sep 19 '22 at 14:54
0

I will assume that you already know that, the full-expression of the initialization of a constexpr variable V has to be a constant expression ([dcl.constexpr]/10) so that the compiler, at compile-time, can replace each occurrence of expression V with its corresponding value.

And in order to know whether an expression is a constant expression, you have to firstly know whether the expression is a core constant expression. The standard has a whole subclause described in [expr.const] defines how to know whether an expression is a core constant expression.

From my point of view, any expression E is a core constant expression unless E evaluates any of the constraints in [expr.const]/5.

Considering what has been said, since your variable v is a constexpr, its initializer (rf in this case) has to be a constant expression. Ask yourself first: Is rf a core constant expression? To know that, ask yourself again: Is rf evaluates any of [expr.const]/5? In your case, it does evaluate lvalue-to-rvalue conversion (5.8) and neither (5.8.1) nor (5.8.2) is satisfied.

That's, The lvalue-to-rvalue conversion is applied to the non-volatile glvalue rf, but the expression rf is neither usable in a constant expression (because it is not potentially-constant constant-initialized or constexpr) nor refers to an object whose lifetime began within the evaluation of expression rf (because the lifetime of the variable rf began before the evaluation of the expression rf). Hence, the expression rf is not a core constant expression and therefore not a constant expression (can't be used as an expression anywhere when a constant expression is required)

Also, note that both [expr.const]/(5.10) and [expr.const]/(5.12) have not been reached yet: (5.8) is tried first.

mada
  • 1,646
  • 1
  • 15
  • So, how about the case if `rf` were declared as `int const rf`? – xmh0511 Sep 20 '22 at 03:59
  • 1
    @xmh0511 - The top-level `const` will be dropped from the function parameter type, per [dcl.fct]/5. – mada Sep 20 '22 at 05:45
  • No, the standard didn't say the variable introduced by the *parameter-declaration* would have the adjusted type. See [dcl.type.decltype] p1.3, the result of `decltype(rf)` will be `const int`. – xmh0511 Sep 21 '22 at 02:23
  • 1
    The actual reason for my question is that even though the parameter is declared as `int const rf`, it cannot be a *constant-initialized* variable because [expr.const] p2.1 is not satisfied here. – xmh0511 Sep 21 '22 at 02:46
  • _"No, the standard didn't say the variable introduced by the parameter-declaration would have the adjusted type."_ I think that, per [expr.type]/2, **before any further analysis**, the top-level cv-qualifiers are dropped. But that doesn't mean that `rf++` is allowed: Indeed the parameter type is still _const-qualified_ – mada Sep 21 '22 at 04:53
  • Again, the argument in the call is not an **initializer**, since the *parameter-declaration* does not comprise an initializer. – xmh0511 Sep 21 '22 at 05:12
  • _"Again, the argument in the call is not an initializer"_ I think this is something new to me. Where does the standard say that? And if the parameter has a default argument, Is it also not considered an **initializer**? – mada Sep 21 '22 at 05:20
  • You just need to check the grammar of *parameter-declaration*(dcl.fct#3), and the grammar of initializer(dcl.init#general-1) – xmh0511 Sep 21 '22 at 05:23
  • _"Again, the argument in the call is not an initializer"_ -- Per [expr.call]/1 _"A function call is a postfix expression followed by parentheses containing a possibly empty, comma-separated list of **initializer-clauses** which constitute the arguments to the function."_ – mada Sep 21 '22 at 08:42
  • *initializer-clause* does not mean it is an initializer. Conversely, an initializer can comprise an *initializer-clause*. Similarly, an id-expression is not necessary to be a declarator-id(i.e. the id-expression is an expression) but a declarator-id is an id-expression. – xmh0511 Sep 21 '22 at 09:36
  • @xmh0511 - What you're saying exactly means that the variable `rf` is not usable in constant expression because it's not constant-initialized because it doesn't have an initializer (this requirement for [expr.const]/(2.1)). Even if the function is called with an argument, `rf` is still not constant-initialized because, as you said, an argument is not an initializer. Am I correct? – mada Sep 21 '22 at 11:21