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

Is the constructor call a prvalue and what's the type of it? #4837

Closed
xmh0511 opened this issue Aug 24, 2021 · 7 comments
Closed

Is the constructor call a prvalue and what's the type of it? #4837

xmh0511 opened this issue Aug 24, 2021 · 7 comments

Comments

@xmh0511
Copy link
Contributor

xmh0511 commented Aug 24, 2021

[intro.execution] p5

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.

Hence, the implicit call of a constructor should be considered as an expression.

[class.ctor.general] p2

A constructor is used to initialize objects of its class type.

As well, some rules in the standard also imply a constructor call is used to initialize an object, such as

If overload resolution is successful, the selected constructor is called to initialize the object, with the initializer expression or expression-list as its argument(s).

Hence, the constructor call should be categorized to prvalue as per [basic.lval] p1

A prvalue is an expression whose evaluation initializes an object or computes the value of an operand of an operator, as specified by the context in which it appears, or an expression that has type cv void.

However, in the current standard, there is no common rule that phrases what's the type of a constructor call(i.e. what's the type of that prvalue). Furthermore, after the amending of #4737, this issue seems to become more obscure.

@xmh0511 xmh0511 changed the title Is a constructor call a prvalue? Is the constructor call a prvalue and what's the type of it? Aug 25, 2021
@frederick-vs-ja
Copy link
Contributor

IMHO the item "expression" used in [intro.execution] p5 is only used for definition of full-expression.
So, according to the definition of "expression" (in [expr.comma] p1), a constructor call is not itself an expression (in the general meaning among the standard), and hence doesn't have type and value category.

However, one can argue that the definition in [expr.comma] p1 is the definition of the grammar production. The "definition" of "expression" looks like the sentence in [expr.pre] p1 (which also excludes constructor calls), but it's in a non-normative note.

@jensmaurer
Copy link
Member

Note "is considered to be an expression for the purposes of this definition."

So, this only refers to "this definition", which is the definition of "full-expression".

A constructor call is always caused by some language construct, e.g. an explicit type conversion, and I believe we do specify the value category in those situations. (If there is anything amiss, please be specific.)

I don't see a defect here.

@xmh0511
Copy link
Contributor Author

xmh0511 commented Aug 30, 2021

@jensmaurer Consider this example

struct A{
  A() = default;
  A(int){}
};
A t = A(0);  //#1

According to [expr.type.conv#2], [expr.cast], A(0) is equivalent to static_cast<A>(0), and as per [expr.static.cast#4]

Otherwise, the result object is direct-initialized from E.

the initialization occurs in #1 is ultimately equivalent to as if it is that

A t(0);

We do specify the value category and type for the expression static_cast<A>(0), however, we do not specify these properties for the constructor call whose evaluation actually initialized the result object, in the context of that the result object is direct-initialized from E. I believe, the constructor call for A::A(int) certainly occurs in the full-expression, which can be considered as an expression.

@jensmaurer
Copy link
Member

Again, the mention of expression near the full-expression definition is just for the purposes of defining full-expression, and the wording says so.

In your example above, the value category is only relevant for the expressions 0 and A(0) (and those value categories are well-specified); everywhere else, we don't syntactically have an expression and we never ask for the value category. Thus, it doesn't matter what value category a constructor call is.

@xmh0511
Copy link
Contributor Author

xmh0511 commented Aug 30, 2021

@jensmaurer Assume we're checking whether the full-expression of the initialization is a constant expression

The constant expression is defined as

A constant expression is either a glvalue core constant expression that..., or a prvalue core constant expression whose value satisfies the following constraints.

In the above example, if we modify A(int){} to constexpr A(int){}, I wonder whether the constant expression is a glvalue or pralue, what stuff determines the value category of the constant expression?

@jensmaurer
Copy link
Member

Which "the constant expression"? Which expression are you looking at?

@xmh0511
Copy link
Contributor Author

xmh0511 commented Aug 30, 2021

struct A{
  A() = default;
  constexpr A(int){}
};
constexpr A t = A(0);  //#1

According to [dcl.constexpr] p10, the full-expression of the initialization at #1 shall be a constant expression. That means the constant expression is either a glvalue core const expression or prvalue core constant expression that satisfies the requirements, respectively. In this case, what stuff determines the value category of the "full-expression of the initialization"?

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