[cfe-dev] defaulted default constructor with initializer

Kal b17c0de at gmail.com
Fri Apr 17 00:48:37 PDT 2015


Am 17.04.15 um 08:55 schrieb Richard Smith:
> On Thu, Apr 16, 2015 at 11:33 PM, Kal <b17c0de at gmail.com 
> <mailto:b17c0de at gmail.com>> wrote:
>
>     Am 17.04.15 um 01:48 schrieb Richard Smith:
>>     On Thu, Apr 16, 2015 at 10:16 AM, Kal <b17c0de at gmail.com
>>     <mailto:b17c0de at gmail.com>> wrote:
>>
>>         Consider this code:
>>
>>         class A {
>>         public:
>>           struct I {
>>             int i = 0;
>>           };
>>           A(I i = {}) {}
>>         };
>>
>>         With clang 3.6 this doesn't compile:
>>         4 : error: cannot use defaulted default constructor of 'I'
>>         within 'A' outside of member functions because 'i' has an
>>         initializer
>>
>>         But if I change the code to
>>
>>         class A {
>>         public:
>>           struct I {
>>             int i = 0;
>>             I() {}
>>           };
>>           A(I i = {}) {}
>>         };
>>
>>         then the code compiles. Why is this so? Aren't these equivalent?
>>
>>
>>     They're not equivalent. The implicit constructor for A::I also
>>     has a deduced exception specification, and computing that
>>     exception specification requires the initializer for 'A::i' to
>>     have already been parsed.
>     You mean initializer for 'A::I' to have already been parsed? But
>     hasn't the entire class definition for A::I and its initializers
>     already been parsed before A::A?
>
>
> The exception specification for I::I is needed when parsing the 
> default argument for A::A(I). The C++ standard does not say which 
> order the "when the class is complete" elements are parsed; Clang 
> handles them in this order:
>
>  1) attributes (thread safety attributes in particular)
>  2) default arguments and exception specifications
>  3) default member initializers
>  4) function bodies
>
> You can swap some of these around (or handle the delayed parts in 
> purely lexical order), but doing so just changes which set of programs 
> you reject. We handle (3) after (2) because it's unusual for a default 
> argument or exception specification to need a default constructor for 
> the current class (or a nested class). The best way to write portable 
> code is to ensure that nothing in (2) or (3) depends on anything in 
> (2), (3), or (4).
Thanks for clarifying this. BTW how does the standard say the exception 
specifier for defaulted constructors should be derived from the member 
initializers?
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20150417/b23954ec/attachment.html>


More information about the cfe-dev mailing list