수업이 기본 구성이 아닌 이유는 무엇입니까?


28

나는 그 수업을 가지고 있습니다 :

#include <type_traits>

template <typename T>
class A {
public:
    static_assert(std::is_default_constructible_v<T>);

};

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

    A<C> a_m;
};

int main() {
    A<B::C> a;
}

컴파일 할 때 a_m기본 구성 가능하지 않지만 a입니다.

로 변경할 때 C:

struct C {
      int i;
   };

다 괜찮아

Clang 9.0.0으로 테스트되었습니다.


3
GCC 8.3-확인, GCC 9.1 / 9.2-실패
평균

2
C() {}너무, 작동합니다.
평균

3
이것은 나에게 버기 냄새가 난다. Bugzilla에 대한 명백한 일치는 없습니다.
궤도에서 가벼움 경주

2
흥미있는 : static_assertin은 A실패하지만 대신 기본적으로 T내부를 구성하면 A(예 : 멤버를 배치 T t;) 모든 것이 잘 작동합니다. 유형 특성이 당신에게 말하는 것과 실제로 가능한 것 사이에 불일치가 있습니다.
sebrockm

2
@Nicolas True, 그러나 일부 엣지 사례로 인해 여기에 해당되는 것은 없습니다 (특히 cppreference의 동일한 문장이 말했듯 이 기본적으로 내장 유형의 초기화 동작과 일부로 const int x;인해 이니셜 라이저가 없으면 유효하지 않습니다) consthistory)
궤도에서 가벼움

답변:


9

이것은 주석의 본문과 주석에서 언급 한 몇 가지 주요 구현에 의해 허용되지 않지만 완전히 관련이없는 이유로 허용되지 않습니다.

먼저, "책에 의한"이유 :의 인스턴스화 시점은 A<C>표준에 따라 정의 직전이고B , 인스턴스화 시점 std::is_default_constructible<C>은 바로 그 직전에 있습니다.

클래스 템플릿 전문화의 경우, [...] 전문화가 다른 템플릿 전문화 내에서 참조되어 암시 적으로 인스턴스화 된 경우, 전문화가 참조되는 컨텍스트가 템플리트 매개 변수에 의존하고 전문화가 이전에 인스턴스화되지 않은 경우 엔 클로징 템플릿의 인스턴스화에서 인스턴스화 지점은 엔 클로징 템플릿의 인스턴스화 지점 바로 앞에 있습니다. 그렇지 않으면, 그러한 전문화에 대한 인스턴스화 지점은 전문화를 참조하는 네임 스페이스 범위 선언 또는 정의 바로 앞에옵니다.

C이 시점에서 분명히 불완전 하기 때문에 인스턴스화 동작 std::is_default_constructible<C>은 정의되지 않습니다. 그러나이 규칙을 변경하는 핵심 문제 287을 참조하십시오 .


실제로 이것은 NSDMI와 관련이 있습니다.

  • NSDMI는 파싱이 지연되기 때문에 이상합니다. 표준 용어로는 "완전한 클래스 컨텍스트"입니다.
  • 따라서 = 0원칙적으로 B아직 선언되지 않은 것을 참조 할 수 있으므로 구현은로 끝날 때까지 구문 분석하려고 시도 할 수 없습니다 B.
  • 클래스를 완성하려면 C생성자가 선언되지 않은 특수 멤버 함수, 특히 기본 생성자의 암시 적 선언이 필요합니다 .
  • 해당 선언의 일부 (constexpr-ness, noexcept-ness)는 NSDMI의 속성에 따라 다릅니다.
  • 따라서 컴파일러가 NSDMI를 구문 분석 할 수 없으면 클래스를 완료 할 수 없습니다.
  • 결과적으로 인스턴스화하는 시점 A<C>에서 그것이 C불완전 하다고 생각합니다 .

구문 분석이 지연된 영역을 다루는이 전체 영역은 구현 차이가 수반되어 상당히 과소 평가되었습니다. 정리하기까지 시간이 걸릴 수 있습니다.


0

정의되지 않은 동작 :

위의 템플릿 인스턴스화가 직접 또는 간접적으로 불완전한 유형에 의존하고 해당 유형이 가상적으로 완료된 경우 해당 인스턴스화가 다른 결과를 낳을 수있는 경우 동작이 정의되지 않습니다.


7
C가 왜 불완전합니까?
interjay December

1
@interjay, C완료되었습니다 B. 그리고 B::C에 간접적으로 의존합니다 B.
Evg

1
@Evg "직접 또는 간접적으로 의존"텍스트는 cppreference.com에만 나타납니다. 표준은 단지 타입 T가 완전해야한다고 말합니다.
interjay December


2
@ interjay 나는이 문구의 대부분을 썼습니다. 우리가 말하려는 것은 1) 불완전한 유형이 완료 될 때 나중에 ODR 위반을 유발할 수있는 방식으로 특성을 인스턴스화하면 정의되지 않습니다. 그리고 2) 프로그램에서 실제로 ODR 위반을 일으키지 않더라도 정의되지 않으므로 표준 라이브러리 구현은 특성이 원하는 경우 특성이 사용되는 시점을 진단하도록 선택할 수 있습니다. 경우 C경우 답변을 변경할 수있는 몇 가지 이상한 SFINAE와 기본 생성자 템플릿이 B완료를 다르게하고 있는지, 형질가에 따라 달라집니다.
TC
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.