Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[expr.const] "converted expression is a constant expression" #4856

Open
xmh0511 opened this issue Sep 1, 2021 · 6 comments
Open

[expr.const] "converted expression is a constant expression" #4856

xmh0511 opened this issue Sep 1, 2021 · 6 comments

Comments

@xmh0511
Copy link
Contributor

xmh0511 commented Sep 1, 2021

Since we define the concept about implicit conversion in [conv]

An expression E can be implicitly converted to a type T if and only if the declaration T t=E; is well-formed, for some invented temporary variable t ([dcl.init]).

The effect of any implicit conversion is the same as performing the corresponding declaration and initialization and then using the temporary variable as the result of the conversion. The result is an lvalue if T is an lvalue reference type or an rvalue reference to function type ([dcl.ref]), an xvalue if T is an rvalue reference to object type, and a prvalue otherwise. The expression E is used as a glvalue if and only if the initialization uses it as a glvalue.

Consider the rule in [expr.const] p10

A converted constant expression of type T is an expression, implicitly converted to type T, where the converted expression is a constant expression and the implicit conversion sequence contains only

Is this equivalent to saying, we model a declaration

T  t = E;

the t is the "converted expression"? Is it equivalent to saying, we require the prvalue t shall be a constant expression? Which should first satisfy [expr.const] p5. However, as a prvalue, we do not supply a result object for it, how do we retrospect what would evaluate when evaluating the initialization that occurs in the model declaration? Specifically, in this example

struct A{
  constexpr operator bool(){
        return true;
   }
};
template<bool B>
struct C{};
constexpr A a;
C<a> c; //#1

At #1, a should be a converted constant expression of type bool. The implicit conversion would apply to a, which is equivalent to model a declaration and perform the initialization

bool conv_result = a;  // #0 evaluate the initialization will evaluate the "constexpr operator bool"
C<conv_result > c; //  #1'

The conv_result is a prvalue, but how do we retrospect the initialization that occurs at #0 when we do not supply a result object to make the initialization evaluate? It seems if we say that

the full-expression of the initialization associated with the converted expression is a constant expression when interpreted as a constant-expression

will make the meaning more consistent with the definition of implicit conversion. I think this is also suitable for glvalue(converted expression).

struct A{
    A(){ std::cout<<"abc\n"; }
};
template<A& rf>
struct C{};
A a;
C<a> c; 
/*
  A& rf = a;  // the full-expression of the initialization shall be a  constant expression
*/
@jensmaurer
Copy link
Member

In my view, the phrasing T t = E; simply determines how the conversion works and which conversion functions etc. are invoked. Once that is done, we have a converted expression f(E) (here called t) that needs to be a constant expression. You seem to be concerned that, for the prvalue case, the actual initialization isn't covered by the "constant expression" constraints. I don't think so, because in the cases where we yield a prvalue, we actually have a (symbolic) initialization of that prvalue in view. E.g. a called function would use copy-initialization in the "return" statement, which imposes the appropriate constraints, even if the prvalue model does not supply an actual target object until later / outside.

@xmh0511
Copy link
Contributor Author

xmh0511 commented Sep 2, 2021

Presumably, the intent should be that meaning. However, when we say "X" (shall)is a constant expression, we just concern about whether "X" itself satisfies the requirements to be a constant expression. Such as

static int value = random();  //#1
constexpr int& rf = value;  // #2

As per [dcl.constexpr] p10

In any constexpr variable declaration, the full-expression of the initialization shall be a constant expression ([expr.const]).

In this example, we require the full-expression of the initialization at #2 should be a constant expression, especially, we only concern whether lvalue value is a constant expression that is a glvalue core constant expression. At this declaration, evaluate value won't violate any restriction in [expr.const] p5, which also says we don't need to concern about how the value is initialized. Analogy, when we say "converted expression" is a constant expression, we only concern whether that "converted expression" itselft satisfy the requirement to be a constant expression, since there is no result object in such as "template-argument-list", "explicit(constant-expression)", "noexcept(constant-expression)", "[constant-expression]", evaluate such a prvalue seems not to have an effect(i.e. recover the scene of the process of the initialization). This is my concern in this issue.

As you said, we should consider the process of the initialization in this context, however, if we use the way of interpreting "X shall(is) a constant expression" to interpret "converted expression", as aforementioned, it seems a bit contradict, and "converted expression is a constant expression" actually may not expound the intent that we should check the emulated initialization imposing on that prvalue("converted expression").

In other words, we need to inspect what will happen(evaluate) in the whole implicit conversion that converts the source language construct to the expected target one, the "converted expression" is just the result after performing that sequence of these evaluations, we cannot recall the whole process just through the result, it is a bit philosophical utterance but is true.

Maybe, change it to that will be more clear

the implicit conversion sequence is a constant expression when interpreted as a constant-expression.

Then evaluate this constant-expression will be equivalent to performing the corresponding declaration and initialization.

@frederick-vs-ja
Copy link
Contributor

frederick-vs-ja commented Sep 5, 2021

I suppose you shouldn't think in the way that "considers a variable definition an expression". It's obvious that T t = E; is only used for determination of well-formedness and which conversions are used.

IMO conversions and object/reference initializations need different "interpretations" when determining whether they are constant. And it is more consistent for me to include "expression s (grammar productions) plus needed implicit conversions to target types" into expressions.

@xmh0511
Copy link
Contributor Author

xmh0511 commented Sep 5, 2021

T t = E; is a convenient way to expound that conversion and examine whether the conversion is well-formed. [conv#general-6] explicitly says that

The effect of any implicit conversion is the same as performing the corresponding declaration and initialization and then using the temporary variable as the result of the conversion.

They're arguably equivalent.

it is more consistent for me to include "expression s (grammar productions) plus needed implicit conversions to target types" into expressions.

Isn't that what contents I claimed to improve in this issue? I prefer to interpret the implicit conversion as a constant-expression, and evaluate this constant-expression can view what stuff the implicit conversion needs to evaluate. Since we have used a similar utterance to expound "full-expression of the initialization". According to [conv#general-6], the evaluation of this constant-expression would equal to perform the initialization in the declaration

T t = E;

This proposal may make these rules consistent.

@frederick-vs-ja
Copy link
Contributor

IMO it's better to specify expressions, constant expressions, and implicit conversions in such way that no additional "interpret" is needed.
Given that a conversion can have its type and value category, while a variable definition shouldn't have, I think a formal definition of "expression" that includes implicit conversions (and thus more general than expression) should be present in [expr.pre].

@xmh0511
Copy link
Contributor Author

xmh0511 commented Sep 6, 2021

It is impossible to specify conversion to be an expression without "interpret" as if it is an expression of grammar. Moreover, regardless of the category value or type of the conversion, they're all specified in [conv#general-6]. Redefine them is redundant. We just lack the relevant phrase about the evaluation of the whole process of the conversion, even though, the whole conversion occurs in that context.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants