问题
struct foo
{
struct bar {
~bar() {} // no error w/o this line
};
bar *data = nullptr; // no error w/o this line
foo() noexcept = default; // no error w/o this line
};
Yes, I know, there is another question with exactly the same title, but a somewhat different problem (involving a noexcept
operator and no nested type). The solution suggested there (replacing the constructor of foo
with
foo() noexcept {}
) changes the semantics and it not necessary here: here we have a better answer (hence the question is not a duplicate).
compiler: Apple LLVM version 9.0.0 (clang-900.0.37)
, full error message:
test.cc:44:5: error: default member initializer for 'data' needed within definition of enclosing class 'foo' outside of member functions
foo() noexcept = default;
^
test.cc:41:10: note: default member initializer declared here
bar* data = nullptr;
^
回答1:
This is a clang bug. But there is a simple workaround.
When one defines a special member function as defaulted, the noexcept
specifier is just used to check that the defaulted special member generated by the compiler will be noexcept
, [dcl.sft.dcl.def]:
If a function that is explicitly defaulted is declared with a noexcept-specifier that does not produce the same exception specification as the implicit declaration (18.4), then
— if the function is explicitly defaulted on its first declaration, it is defined as deleted;
— otherwise, the program is ill-formed.
So if you remove the noexcept sepcifier of foo
default constructor, you will not change the semantic, foo
will still be nothrow default constructible:
#include <type_traits>
struct foo
{
struct bar {
~bar() {} // no error w/o this line
};
bar *data = nullptr; // no error w/o this line
foo()= default; // foo is noexcept, weither the declarator contains noexcept or not
};
static_assert(std::is_nothrow_default_constructible<foo>::value);
回答2:
The problem can be solved by defaulting the destructor of the nested class
struct foo
{
struct bar {
~bar() = default; // this fixes it
};
bar *data = nullptr; // no error w/o this line
foo() noexcept = default; // no error w/o this line
};
However, it's not clear to me why/whether this is required by the standard.
来源:https://stackoverflow.com/questions/46866686/default-member-initializer-needed-within-definition-of-enclosing-class-outside