2020年12月22日星期二

what is the meaning of "initializer expression" in the current standard

As for an issue asked in https://github.com/cplusplus/draft/issues/2934, there's no concrete answers in the comment. There are so many times the wording "initializer expression" be referred in section dcl.init

If the destination type is a (possibly cv-qualified) class type:

  • If the initializer expression is a prvalue and the cv-unqualified version of the source type is the same class as the class of the destination, the initializer expression is used to initialize the destination object.

The initializer basically has three forms like:

 = initializer-clause   (expression-list)     {initializer-list}  

I don't find any explicit definition for the concept "initializer expression". However, try to infer it from the section [dcl.init]. I think it seems to be: intro.execution#9

A constituent expression is defined as follows:

  • The constituent expression of an expression is that expression.
  • The constituent expressions of a braced-init-list or of a (possibly parenthesized) expression-list are the constituent expressions of the elements of the respective list.
  • The constituent expressions of a brace-or-equal-initializer of the form = initializer-clause are the constituent expressions of the initializer-clause.

So, initializer expression may refer to the constituent expression of these initializers. I'm not sure whether this supposition is right? Maybe.

If this supposition is right, there's an issue coming here.

According to dcl.init#17.6.1, we know that the prvalue of the same class type as the destination type is used to directly initialize the destination object, as the example says:

T x = T(T(T())); // the initializer is "= T(T(T()))" where the initializer expression is "T(T(T()))"  // is equivalent to  // T x();  although the semantic of this declaration declared a function.    

However, consider this example:

#include <iostream>  struct A{    A(){}    A(int){      std::cout<<"constructor A from int\n";    }    A(A const&){       std::cout<<"copy constructor A\n";    }  };  int main(){    A x = {A{A{A{0}}}};  }  

GCC and Clang both print "constructor A from int". I have to say the initializer is braced-init-list, this case should be processed by list-initialization, whose step is before [dcl.init#17.6.1]. In other words, dcl.init.list#3.6 should apply to this example. Since the element of the initializer list is a prvalue of class type A, so A(A const&) is the selected function, which requests a temporary materialization conversion that applies to the prvalue. The prvalue will initialize the result object which will be bound to the parameter of A(A const&), where [dcl.init#17.6.1] will apply when initializing the result object. The hypothetical code is:

A t = A{A{A{0}}}; // pseudo materialization conversion  A x(t);  

At least, in this example, A(A const&) should be invoked once. However, GCC and Clang do not do so.

Question:

  1. Is my understanding for initializer expression right?
  2. From the behavior of GCC and Clang, why the rule [dcl.init#17.6.1] directly apply to list initialization? I think [dcl.init#17.6.1] should apply to the intervening temporary result object rather than the whole list-initialization.
https://stackoverflow.com/questions/65418296/what-is-the-meaning-of-initializer-expression-in-the-current-standard December 23, 2020 at 10:29AM

没有评论:

发表评论