programing

비 정적 데이터 멤버 및 중첩 클래스 생성자의 클래스 내 초기화를 사용할 때 오류 발생

nasanasas 2020. 9. 10. 07:57
반응형

비 정적 데이터 멤버 및 중첩 클래스 생성자의 클래스 내 초기화를 사용할 때 오류 발생


다음 코드는 매우 사소하며 잘 컴파일되어야한다고 예상했습니다.

struct A
{
    struct B
    {
        int i = 0;
    };

    B b;

    A(const B& _b = B())
        : b(_b)
    {}
};

이 코드는 g ++ 버전 4.7.2, 4.8.1, clang ++ 3.2 및 3.3으로 테스트했습니다. 이 코드 ( http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57770 ) 에 g ++ 4.7.2 segfault가 있다는 사실을 제외 하고 다른 테스트 된 컴파일러는 많이 설명하지 않는 오류 메시지를 제공합니다.

g ++ 4.8.1 :

test.cpp: In constructor ‘constexpr A::B::B()’:
test.cpp:3:12: error: constructor required before non-static data member for ‘A::B::i’ has been parsed
     struct B
            ^
test.cpp: At global scope:
test.cpp:11:23: note: synthesized method ‘constexpr A::B::B()’ first required here 
     A(const B& _b = B())
                       ^

clang ++ 3.2 및 3.3 :

test.cpp:11:21: error: defaulted default constructor of 'B' cannot be used by non-static data member initializer which appears before end of class definition
    A(const B& _b = B())
                    ^

이 코드를 컴파일 가능하게 만드는 것이 가능하며 아무런 차이가 없어야합니다. 두 가지 옵션이 있습니다.

struct B
{
    int i = 0;
    B(){} // using B()=default; works only for clang++
};

또는

struct B
{
    int i;
    B() : i(0) {} // classic c++98 initialization
};

이 코드가 정말 잘못되었거나 컴파일러가 잘못 되었습니까?


이 코드가 정말 잘못되었거나 컴파일러가 잘못 되었습니까?

글쎄, 둘 다. 이 표준에는 결함이 있습니다. 즉 ,에 A대한 이니셜 라이저를 구문 분석하는 동안 완료된 것으로 간주 되는 B::i것과 B::B()(이니셜 라이저를 사용하는 B::i)의 정의 내에서 사용할 수 있다고 A합니다. 그것은 분명히 순환 적입니다. 이걸 고려하세요:

struct A {
  struct B {
    int i = (A(), 0);
  };
  A() noexcept(!noexcept(B()));
};

이것은 모순이 있습니다 : B::B()is implicitly noexceptiff A()does not throw, and A()does not throw iff B::B()is not noexcept . 이 영역에는 많은 다른주기와 모순이 있습니다.

이것은 핵심 문제 13601397에 의해 추적됩니다 . 특히 핵심 문제 1397에서 다음 참고 사항을 참고하십시오.

Perhaps the best way of addressing this would be to make it ill-formed for a non-static data member initializer to use a defaulted constructor of its class.

That's a special case of the rule that I implemented in Clang to resolve this issue. Clang's rule is that a defaulted default constructor for a class cannot be used before the non-static data member initializers for that class are parsed. Hence Clang issues a diagnostic here:

    A(const B& _b = B())
                    ^

... because Clang parses default arguments before it parses default initializers, and this default argument would require B's default initializers to have already been parsed (in order to implicitly define B::B()).


Maybe this is the problem:

§12.1 5. A default constructor that is defaulted and not defined as deleted is implicitly defined when it is odr- used (3.2) to create an object of its class type (1.8) or when it is explicitly defaulted after its first declaration

So, the default constructor is generated when first looked up, but the lookup will fail because A is not completely defined and B inside A will therefore not be found.

참고URL : https://stackoverflow.com/questions/17430377/error-when-using-in-class-initialization-of-non-static-data-member-and-nested-cl

반응형