2

나는 해당 클래스 템플릿의 네임 스페이스로 시작하는 클래스 템플릿의 forward 선언을 사용하는 example1과 example2가 있습니다. 첫 번째 예제는 visual-studio로 제대로 컴파일되지만 두 번째 예제에서는 그렇지 않습니다. 두 컴파일러를 다른 컴파일러 (http://rextester.com)와 비교해 보았습니다. 이제 2 가지 질문이 있습니다 :네임 스페이스를 포함한 클래스 템플릿의 forward 선언으로 인해 컴파일 오류가 발생합니다.

  • 여기를 사용하면 앞쪽 선언에서 네임 스페이스가 잘못된 것 같습니다. 왜 정확히?

  • 비주얼 스튜디오 (2015 및 2017)는 첫 번째 예에서 추가 네임 스페이스로 전달 선언을 허용하지만 두 번째 예에서는 허용되지 않는 것처럼 보입니다. 이거 버그 야?

예 1

#include <vector> 

namespace N1 
{ 
    template <typename T> struct MySystem {}; 
    template <typename T> class Other {}; 

    struct MyClass 
    { 
     MyClass() { typename Dependencies::TYPE_A oTYPE_A; } 

     struct Dependencies 
     { 
      template <typename> 
      class N1::Other; 

      struct TypeX_Dependencies; 

      using TYPE_A = N1::MySystem<N1::Other<TypeX_Dependencies>>; 

      struct TypeX_Dependencies 
      { 
       using TYPE_A = typename Dependencies::TYPE_A; 
      }; 

      using TYPE_X = N1::Other<TypeX_Dependencies>; 
     }; 
    }; 
} 

int main(){ return 0; } 

C++ (GCC 5.4.0)
source_file.cpp:15:23: error: invalid use of template-name ‘N1::Other’ without an argument list class N1::Other;

C++ (연타 3.8.0)
source_file.cpp:15:23: error: non-friend class member 'Other' cannot have a qualified name class N1::Other;
source_file.cpp:15:19: error: forward declaration of class cannot have a nested name specifier class N1::Other;

C++ (VC++ x64/19.00.23506/커뮤니티와 비교 2017 15.4.4)
compiles fine

예 2

#include <vector> 

namespace N1 
{ 
    template <typename T> struct MySystem {}; 
    template <typename T> class Other {}; 

    template <typename T> 
    struct MyClass 
    { 
     MyClass() { typename Dependencies::TYPE_A oTYPE_A; } 

     struct Dependencies 
     { 
      template <typename> 
      class N1::Other; 

      struct TypeX_Dependencies; 

      using TYPE_A = N1::MySystem<N1::Other<TypeX_Dependencies>>; 

      struct TypeX_Dependencies 
      { 
       using TYPE_A = typename Dependencies::TYPE_A; 
      }; 

      using TYPE_X = N1::Other<TypeX_Dependencies>; 
     }; 
    }; 
} 

int main(){ return 0; } 

C++ (GCC 5.4.0)
source_file.cpp:16:23: error: invalid use of template-name ‘N1::Other’ without an argument list class N1::Other;

C++ (연타 3.8.0)
source_file.cpp:16:23: error: non-friend class member 'Other' cannot have a qualified name class N1::Other;
source_file.cpp:16:19: error: forward declaration of class cannot have a nested name specifier class N1::Other;

C++ (vC++ 19.00.23506 for x64/커뮤니티와 비교해도 2017 15.4.4)
source_file.cpp(16): error C3855: 'N1::Other': template parameter 'T' is incompatible with the declaration
source_file.cpp(24): note: see reference to class template instantiation 'N1::MyClass<T>::Dependencies' being compiled
source_file.cpp(29): note: see reference to class template instantiation 'N1::MyClass<T>' being compiled
source_file.cpp(20): error C3203: 'Other': unspecialized class template can't be used as a template argument for template parameter 'T', expected a real type

+0

작동을 위해'Other '을 사용하십시오. –

+1

'struct Dependencies'에 선언 된'Other'가 새로운 클래스인지 아니면 글로벌':: N1 :: Other' 클래스를 참조합니까? – 1201ProgramAlarm

+1

[나를 위해 컴파일] (http://rextester.com/YXXHEH87078). 어쨌든, 왜 처음에는'의존성'내부에서'기타'를 다시 선언 할 필요가 있다고 생각하니? –

답변

1

예, 이것은 버그입니다. [dcl.type.elab]/1에 따르면

,

...elaborated-type-specifier이 선언의 유일한 구성 인 경우, 선언은 명시 적 전문화, 명시 적으로 실체화하지 않는 잘못 형성되거나 다음과 같은 형태 중 하나가된다

  • 클래스 키 속성 지정자 -seq opt 식별자;
  • friend클래스 키::옵트 식별자;
  • friend클래스 키::선택 하간단한 템플릿-ID;
  • friend클래스 키 중첩 이름 지정자 식별자;
  • friend클래스 키 중첩 된 이름 지정template선택 하간단한 템플릿-ID;

당신의 선언 class N1::Other은 명시 적으로 전문화,도 명시 적 인스턴스화도 아니다, 그래서 강조된 형태 (그 friend 선언을 무시)를 가지고있다. nested-name-specifier식별자 앞에 강조 표시되어 있으므로 선언이 잘못되었습니다. 템플릿이없는 다음 예제에서 Clang의 컴파일러 오류는이 문제를 보여줍니다.

namespace N { 
    struct S; 
} 
struct N::S; // error: forward declaration of struct cannot have a nested name specifier 

LIVE EXAMPLE가 (BTW, GCC는이 코드를 받아 단지 선언 할 새로운 아무것도에 대한 경고를 제공합니다. 나는 GCC의 버그 것 같다.) 여기

template-headtemplate <typename> 도움이되지 않기 때문에 class N1::Other 그 자체는 선언을 문법 정의 템플릿 머리에 따라 작성해야하므로 위의 paragragh가 적용됩니다.

대략적으로 동일한 이름을 가진 클래스가 선언 된 범위와 다른 범위의 클래스 선언은 새 클래스를 도입해야합니다.이 경우 중첩 이름 지정자을 사용하거나 정의하지 마십시오. 문법이 정교 유형 지정자 대신에 class-specifier을 형성하기 때문에 이전에 선언 된 클래스이므로 위의 문단은 적용되지 않습니다. 결론적으로이 규칙은 합리적입니다.

관련 문제