C ++ 17에서 보호 된 생성자에 대한 규칙이 변경 되었습니까?
이 테스트 케이스가 있습니다.
struct A{ protected: A(){} };
struct B: A{};
struct C: A{ C(){} };
struct D: A{ D() = default; };
int main(){
(void)B{};
(void)C{};
(void)D{};
}
gcc와 clang은 모두 C ++ 11 및 C ++ 14 모드로 준비합니다. 둘 다 C ++ 17 모드에서 실패합니다.
$ clang++ -std=c++17 main.cpp
main.cpp:7:10: error: base class 'A' has protected default constructor
(void)B{};
^
main.cpp:1:22: note: declared protected here
struct A{ protected: A(){} };
^
main.cpp:9:10: error: base class 'A' has protected default constructor
(void)D{};
^
main.cpp:1:22: note: declared protected here
struct A{ protected: A(){} };
^
2 errors generated.
$ clang++ --version
clang version 6.0.0 (http://llvm.org/git/clang.git 96c9689f478d292390b76efcea35d87cbad3f44d) (http://llvm.org/git/llvm.git 360f53a441902d19ce27d070ad028005bc323e61)
Target: x86_64-unknown-linux-gnu
Thread model: posix
(마스터 브랜치 2017-12-05에서 준비 된 clang.)
$ g++ -std=c++17 main.cpp
main.cpp: In function 'int main()':
main.cpp:7:10: error: 'A::A()' is protected within this context
(void)B{};
^
main.cpp:1:22: note: declared protected here
struct A{ protected: A(){} };
^
main.cpp:9:10: error: 'A::A()' is protected within this context
(void)D{};
^
main.cpp:1:22: note: declared protected here
struct A{ protected: A(){} };
^
$ g++ --version
g++ (GCC) 8.0.0 20171201 (experimental)
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
이 동작 변경은 C ++ 17의 일부입니까 아니면 두 컴파일러 모두의 버그입니까?
존재 의 정의는 C ++ 17 이후 변경되었습니다.
C ++ 17 이전
기본 클래스 없음
C ++ 17 이후
virtual, private, or protected (since C++17)
기본 클래스 없음
즉, for B
and D
는 C ++ 17 이전에 존재 유형이 for B{}
and D{}
, 값 초기화가 수행되고 기본 기본 생성자가 호출 됩니다. protected
기본 클래스의 생성자는 클래스의 생성자에 의해 호출 될 수 있기 때문에 괜찮습니다 .
C ++ 17 일 이후 B
와 D
(그들은 단지 때문에 집계 유형이 될 public
기본 클래스 및 메모를 클래스의 것을 D
위해 다음, 명시 적으로 부도 기본 생성자 (11) C ++ 이후 집계 유형에 허용되는) B{}
과 D{}
, 집계 초기화가 될 것입니다 수행,
각
direct public base, (since C++17)
배열 요소 또는 비 정적 클래스 멤버는 클래스 정의의 배열 첨자 / 모양 순서대로 초기화 목록의 해당 절에서 복사 초기화됩니다.이니셜 라이저 절의 수가 멤버 수보다 적
and bases (since C++17)
거나 이니셜 라이저 목록이 완전히 비어있는 경우, 나머지 멤버and bases (since C++17)
는by their default initializers, if provided in the class definition, and otherwise (since C++14)
일반 목록 초기화 규칙에 따라 빈 목록으로 초기화됩니다 (비 클래스 유형에 대해 값 초기화를 수행하고 기본 생성자가있는 비 집계 클래스 및 집계에 대한 집계 초기화). 참조 유형의 멤버가 이러한 나머지 멤버 중 하나 인 경우 프로그램은 잘못된 것입니다.
즉, 기본 클래스의 하위 객체 값으로 초기화 직접 생성자 것이다 수단 B
과 D
우회이고; 그러나의 기본 생성자는 A
이면 protected
코드가 실패합니다. ( A
사용자가 제공 한 생성자가 있으므로 집계 유형이 아닙니다.)
BTW : C
(사용자 제공 생성자 사용) C ++ 17 전후의 집계 유형이 아니므로 두 경우 모두 괜찮습니다.
C ++ 17에서는 집계에 대한 규칙이 변경되었습니다.
예를 들어 이제 C ++ 17에서이 작업을 수행 할 수 있습니다.
struct A { int a; };
struct B { B(int){} };
struct C : A {};
struct D : B {};
int main() {
(void) C{2};
(void) D{1};
}
우리는 생성자를 상속하지 않습니다. 17 ++ C에서 C
하고 D
있습니다 지금은 기본 클래스를 경우에도 집계합니다.
를 사용 {}
하면 집계 초기화가 시작되고 매개 변수를 전송하지 않는 것은 외부에서 부모의 기본 생성자를 호출하는 것과 동일하게 해석됩니다.
예를 들어, 클래스 D
를 다음과 같이 변경하여 집계 초기화를 비활성화 할 수 있습니다 .
struct B { protected: B(){} };
struct D : B {
int b;
private:
int c;
};
int main() {
(void) D{}; // works!
}
이는 액세스 지정자가 다른 멤버가있는 경우 집계 초기화가 적용되지 않기 때문입니다.
Works를 사용하는 이유 = default
는 사용자가 제공 한 생성자가 아니기 때문입니다. 이 질문에 대한 자세한 정보 .
참고 URL : https://stackoverflow.com/questions/47656093/changed-rules-for-protected-constructors-in-c17
'ProgramingTip' 카테고리의 다른 글
Docker- 컨테이너가 실행되고 있지 않습니다. (0) | 2020.12.05 |
---|---|
Pythonic 방법은 무엇입니까? (0) | 2020.12.05 |
ThreadPool 대 작업 (0) | 2020.12.05 |
사실과 이론의 차이? (0) | 2020.12.05 |
Angular의 빌드 및 실행 방법 (0) | 2020.12.05 |