struct A{
A(){}
};
union C{
A a;
int b = 0;
};
int main(){
C c;
}
위의 코드에서 GCC와 Clang은 모두 공용체의 기본 생성자 C
가 삭제 된 것으로 정의되어 있다고 불평합니다 .
그러나 관련 규칙은 다음과 같이 말합니다.
클래스 X의 기본 생성자는 다음과 같은 경우 삭제 된 것으로 정의됩니다.
- X는 중요하지 않은 기본 생성자가있는 변형 멤버가 있고 X의 변형 멤버에는 기본 멤버 이니셜 라이저가없는 공용체입니다 .
- X는 중요하지 않은 기본 생성자가있는 변형 멤버 M이 있고 M을 포함하는 익명 공용체의 변형 멤버에는 기본 멤버 initializer 가없는 비 조합 클래스입니다 .
강조된 문구에 주목하십시오. IIUC 예제에서 변형 멤버 b
에는 기본 멤버 이니셜 라이저가 있으므로 기본 기본 생성자는 삭제 된 것으로 정의되어서는 안됩니다. 이러한 컴파일러가이 코드를 잘못된 형식으로보고하는 이유는 무엇입니까?
정의를 다음 C
으로 변경하면
union C{
A a{};
int b;
};
그러면 모든 컴파일러 가이 코드를 컴파일 할 수 있습니다. 이 동작은 규칙이 실제로 의미하는 바를 암시합니다.
X가 아닌 사소한 기본 생성자와 변형 부재에 대한 공급 초기화없이 기본 구성원이 노동 조합이다 변형 구성원을
이것이 컴파일러 버그입니까, 아니면 그 규칙의 모호한 표현입니까?
이것은 CWG 2084 를 통해 C ++ 14와 C ++ 17 사이에서 변경되었으며 , 이는 (모든) 공용체 멤버의 NSDMI가 기본 기본 생성자를 복원 할 수 있도록 허용하는 언어를 추가했습니다.
CWG 2084와 함께 제공되는 예는 귀하와 미묘하게 다릅니다.
struct S {
S();
};
union U {
S s{};
} u;
여기서 NSDMI는 중요하지 않은 멤버에있는 반면 C ++ 17에 채택 된 문구는 모든 멤버 의 NSDMI가 기본 생성자를 복원 할 수 있도록합니다 . DR에 기록 된대로
NSDMI는 기본적으로 mem-initializer의 구문 설탕입니다.
즉, NSDMI on int b = 0;
은 기본적으로 mem-initializer 및 빈 본문을 사용하여 생성자를 작성하는 것과 같습니다.
C() : b{/*but use copy-initialization*/ 0} {}
옆으로, 그 보장 원칙으로 최대 노조의 한 변형 멤버는 NSDMI 약간의 절에 숨겨져있다 class.union.anon :
4-[...] Union의 Variant 멤버는 기본 멤버 이니셜 라이저를 가질 수 있습니다.
내 가정은 gcc와 Clang이 이미 위 (중요하지 않은 공용체 멤버의 NSDMI)를 허용했기 때문에 완전한 C ++ 17 지원을 위해 구현을 변경해야한다는 것을 깨닫지 못했다는 것입니다.
이것은 2016 년에 std-discussion 목록에서 논의되었으며 , 귀하와 매우 유사한 예가 있습니다.
struct S {
S();
};
union U {
S s;
int i = 1;
} u;
결론은 clang과 gcc가 거부에 결함이 있다는 것입니다. 당시에는 오해의 소지가있는 메모가 있었지만 결과적으로 수정 되었습니다.
Clang의 경우 버그는 https://bugs.llvm.org/show_bug.cgi?id=39686 이며 변형 멤버 N3690 / N4140 대 N4659 / N4727로 인해 삭제 된 암시 적으로 정의 된 생성자 에서 SO로 다시 돌아 갑니다 . gcc에 해당하는 버그를 찾을 수 없습니다.
참고 MSVC가 제대로 수용 하고,이 초기화 c
에 .b = 0
있다, dcl.init.aggr 당 올바른 :
5-[...] 집계가 공용체이고 이니셜 라이저 목록이 비어 있으면
- 5.4-변형 멤버에 기본 멤버 이니셜 라이저가있는 경우 해당 멤버는 기본 멤버 이니셜 라이저에서 초기화됩니다. [...]
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다