Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Default member initializer needed within definition of enclosing class outside of member functions" - is my code ill-formed?

#include <utility>  struct foo {     int x{0};     foo() noexcept = default;     void f() noexcept(noexcept(std::declval<foo&>())) {} };  int main() {  } 

live example on godbolt


The code above compiles with any version of g++ I tested, and with clang++ from 3.6 to 3.9.1, but does not compile with clang++ 4.0.0:

test.cpp:6:5: error: default member initializer for 'x' needed within  definition of enclosing class 'foo' outside of member functions     foo() noexcept = default;     ^ type_traits:126:26: note: in instantiation of template  class 'std::is_function<foo &>' requested here     : public conditional<_B1::value, _B1, __or_<_B2, _B3, _Bn...>>::type                         ^ type_traits:154:39: note: in instantiation of template  class 'std::__or_<std::is_function<foo &>,     std::is_reference<foo &>, std::is_void<foo &> >' requested here     : public integral_constant<bool, !_Pp::value>                                     ^ type_traits:598:14: note: in instantiation of template  class 'std::__not_<std::__or_<std::is_function<foo &>,     std::is_reference<foo &>, std::is_void<foo &> > >' requested here     : public __not_<__or_<is_function<_Tp>, is_reference<_Tp>,             ^ type_traits:121:26: note: in instantiation of template  class 'std::is_object<foo &>' requested here     : public conditional<_B1::value, _B1, _B2>::type                         ^ type_traits:635:14: note: in instantiation of template  class 'std::__or_<std::is_object<foo &>,     std::is_reference<foo &> >' requested here     : public __or_<is_object<_Tp>, is_reference<_Tp>>::type             ^ type_traits:1667:33: note: in instantiation of template  class 'std::__is_referenceable<foo &>' requested here template<typename _Tp, bool = __is_referenceable<_Tp>::value>                                 ^ type_traits:1678:14: note: in instantiation of default  argument for '__add_rvalue_reference_helper<foo &>'     required here     : public __add_rvalue_reference_helper<_Tp>             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ type_traits:2267:12: note: in instantiation of template  class 'std::add_rvalue_reference<foo &>' requested     here     inline typename add_rvalue_reference<_Tp>::type         ^ wtfff.cpp:7:32: note: while substituting explicitly-specified  template arguments into function template 'declval'     void f() noexcept(noexcept(std::declval<foo&>())) {}                             ^ wtfff.cpp:5:9: note: default member initializer declared here     int x{0};         ^ 

Is my code ill-formed? If so, what's the meaning of the error?

Note that removing the noexcept from the constructor or the {0} initializer from x will make the code compile.

like image 821
Vittorio Romeo Avatar asked May 06 '17 10:05

Vittorio Romeo


1 Answers

Your code is fine from what I can tell. Clang seems to struggle with the = default constructor rather than just defining a default constructor manually. It has the following spiel in its source code about it:

DR1351: If the brace-or-equal-initializer of a non-static data member invokes a defaulted default constructor of its class or of an enclosing class in a potentially evaluated subexpression, the program is ill-formed.

This resolution is unworkable: the exception specification of the default constructor can be needed in an unevaluated context, in particular, in the operand of a noexcept-expression, and we can be unable to compute an exception specification for an enclosed class.

Any attempt to resolve the exception specification of a defaulted default constructor before the initializer is lexically complete will ultimately come here at which point we can diagnose it.

I think it may be incorrectly picking up the error, personally. But it specifially mentions "defaulted default constructor".

The following seems to work:

#include <utility>  struct foo {     int x{0};     foo() noexcept {} // = default;     void f() noexcept(noexcept(std::declval<foo&>())) {} };  int main() {  } 
like image 141
Mitch Avatar answered Sep 22 '22 13:09

Mitch