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

时光怂恿深爱的人放手 提交于 2019-12-10 03:09:11

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!