클래스 템플릿의 중첩 클래스가 특수화를 통해서만 정의 된 코드를 거부하기 위해 Clang이 올바른가요?


17

다음과 같은 클래스 템플릿이 제공됩니다.

template<typename T>
struct Outer
{
    struct Inner;

    auto f(Inner) -> void;
};

우리는 정의 Inner 각 전문 분야에 대해 별도로 합니다 Outer.

template<>
struct Outer<int>::Inner {};

template<>
struct Outer<double>::Inner {};

그런 다음 멤버 함수를 정의하십시오. f 모든 전문화에 대해 한 번Outer .

auto Outer<T>::f(Inner) -> void
{

}

그러나 Clang (9.0.0)은 다음과 같이 불평합니다.

error: variable has incomplete type 'Outer::Inner'

auto Outer<T>::f(Inner) -> void

                      ^

Inner다른 모든 전문화에 대한 정의를 제공하여 컴파일러 오류를 피할 수 있습니다.Outer .

template<typename T>
struct Outer<T>::Inner {};

또는 정의하여 f 각 전문 분야에 대해 별도로 :

template<>
auto Outer<int>::f(Inner) -> void
{

}

template<>
auto Outer<double>::f(Inner) -> void
{

}

GCC와 MSVC는 모두 초기 코드를 받아들이며, 이는 질문을 제기합니다. 이것이 Clang 버그입니까, 아니면 세 가지 중에서 유일한 준수 구현입니까?

컴파일러 탐색기를 사용해보십시오


Inner의 전문화는 관련이 없으며 제거해도 컴파일 결과가 변경되지 않습니다.
n. '대명사'm.

@n. '대명사입니다. 무슨 말인지 잘 모르겠습니다. 모두 의 정의를 추가하는 Inner다른 모든 전문화를 들어정의 f각각의 전문성에 대해 개별적으로 해결 컴파일 오류입니다.

다시 읽어 봅시다. 제거해도 컴파일 결과가 변경되지 않습니다 . 추가하지 않고 제거합니다. gcc clang
n. '대명사'm.

@n. '대명사입니다. 나는 당신이 지금 무슨 뜻인지 알지만 여전히 이상한 말입니다. 내 질문의 요점은 제공되는 Inner각 전문 분야에 대한 정의에도 불구하고 불완전한 유형으로보고 되었다는 것 입니다 Outer. Inner정의를 제거하면 분명히 불완전한 유형이 될 것입니다.
15:37에

"정의를 제거하면 명백히 내부가 불완전한 유형이 될 것입니다."아니오 "전혀 아예 없습니다. 전문화는 완전히 별개의 템플릿이며 기본 템플릿에 전혀 영향을 미치지 않습니다.
n. '대명사'm.

답변:


4

Clang이 코드를 거부하는 것이 잘못되었다고 생각합니다. 함수 선언과 정의는 어떻게 비교됩니까?

auto f(typename T::Inner) -> void;

// ...

template<typename T>
auto Outer<T>::f(typename T::Inner) -> void
{ }

이 예에서는 T::Inner분명히 종속 유형입니다. 따라서 Clang은 인스턴스화 할 때까지 불완전하다고 가정하지 않을 수 있습니다. 귀하의 예에서도 마찬가지입니까? 나는 그렇게 말할 것입니다. 우리는 이것을 표준으로 가지고 있습니다.

[temp.dep.type]

5 이름은 인 현재 인스턴스의 멤버 가 있다면

  • 조회 할 때 규정되지 않은 이름은 현재 인스턴스화 또는 클래스의 비 종속 기본 클래스 인 클래스의 구성원을 하나 이상 참조합니다. [참고 : 이것은 클래스 템플릿의 정의로 둘러싸인 범위에서 이름을 찾을 때만 발생할 수 있습니다. — 끝 참고]
  • ...

이름이 현재 인스턴스화의 멤버 인 경우 현재 인스턴스화종속 멤버 인 이름은 조회시 현재 인스턴스화되는 클래스의 멤버를 하나 이상 참조합니다.

9 유형은

  • ...
  • 알려지지 않은 전문화의 일원
  • 현재 인스턴스화의 종속 멤버 인 중첩 클래스 또는 열거
  • ...

따라서 9 항의 첫 글 머리표가이 사건을 다룬다 typename T::Inner. 그것은 의존적 유형입니다.

한편 귀하의 사건은 두 번째 총알로 덮여 있습니다. Outer::Inner의 현재 인스턴스화에서 발견되는 이름이며 Outer, Outer기본 클래스가 아니라 자체 에서 발견됩니다 . 따라서 현재 인스턴스화의 종속 멤버가됩니다. 이 이름은 중첩 클래스를 나타냅니다. 즉, 두 번째 글 머리 기호의 모든 조건이 적용되므로Outer::Inner 종속 유형도 작성됩니다!

두 경우 모두 종속 유형이 있으므로 컴파일러는 종속 유형과 동일하게 취급해야합니다. 내 결론은 GCC와 MSVC가 옳다는 것입니다.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.