비 정적 데이터 멤버 및 중첩 클래스 생성자의 클래스 내 초기화를 사용할 때 오류 발생
다음 코드는 매우 사소하며 잘 컴파일되어야한다고 예상했습니다.
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 noexcept
iff A()
does not throw, and A()
does not throw iff B::B()
is not noexcept
. 이 영역에는 많은 다른주기와 모순이 있습니다.
이것은 핵심 문제 1360 및 1397에 의해 추적됩니다 . 특히 핵심 문제 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.
'programing' 카테고리의 다른 글
매개 변수와 함께 함수에 대한 참조를 어떻게 전달할 수 있습니까? (0) | 2020.09.10 |
---|---|
MySQL의 ORDER BY RAND () 함수를 어떻게 최적화 할 수 있습니까? (0) | 2020.09.10 |
RESTful 웹 서비스를 보호하는 방법은 무엇입니까? (0) | 2020.09.10 |
Spring Boot 시작 시간 단축 (0) | 2020.09.10 |
업스트림의 호스트를 찾을 수없는 경우 nginx가 충돌하지 않도록 설정 (0) | 2020.09.10 |