다른 컴파일러와 함께 VoidT를 사용하는 SFINAE는 다른 결과로 이어집니다


10

다음 코드를 고려하십시오.

template <typename T> using VoidT = void;

class A {
public:
   using TEST = int;
};

class C {
public:
   using DIFFERENT = int;
};

template <typename T, typename Enable = void>
class B {
public:
   B() = delete;
};

template <typename T>
class B<T, VoidT<typename T::TEST>> {
public:
   B() = default;
};

template <typename T>
class B<T, VoidT<typename T::DIFFERENT>> {
public:
   B() = default;
};

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

   return 0;
}

g ++-4.8.5를 사용하여이 코드를 컴파일하면 다음과 같은 오류 메시지가 나타납니다.

~/test/compile_test> g++ -std=c++11 test.cpp

test.cpp:31:7: error: redefinition of ‘class B<T, void>’

test.cpp:24:7: error: previous definition of ‘class B<T, void>’

그러나 g ++-8.3 (예 : ideone)을 사용하여 컴파일하면 코드가 컴파일되고 다른 전문화가 올바르게 처리됩니다. 이것은 GCC의 버그입니까? 아니면 어떻게 든 정의되지 않은 동작을 호출합니까 (따라서 컴파일러 동작의 차이는 문제가됩니다-정의되지 않았습니다)?

답변:


9

GCC의 버그가 수정 되었습니까?

그것은 표준의 결함이었습니다. 이전 표준 버전에서는 소급 수정되었지만 물론 최신 컴파일러 버전 만 수정됩니다. 그것은이었다 CWG 문제 1558 및 견적에 그것에서 :

별명 템플리트 전문화에서 사용되지 않은 인수 처리는 현재 17.6.7 [temp.alias]로 지정되지 않습니다. 예를 들면 다음과 같습니다.

  #include <iostream>

  template <class T, class...>
    using first_of = T;

  template <class T>
    first_of<void, typename T::type> f(int)
      { std::cout << "1\n"; }

  template <class T>
    void f(...)
      { std::cout << "2\n"; }

  struct X { typedef void type; };

  int main() {
    f<X>(0);
    f<int>(0);
  }

first_of에 대한 참조가 T와 int가 단순히 void와 같거나 대체 실패입니까?

DR 수정이없는 컴파일러의 해결 방법은 도우미를 사용하는 것입니다.

template<typename T> struct voider { using type = void; };
template <typename T> using VoidT = typename voider<T>::type;

클래스 템플릿에서 대체 실패가 보장됩니다.


1
소급 수정은 나를 귀찮게합니다. 그것은 어떤 언어 버전을 설명하는 표준 문서가 없다는 것을 의미합니다.
궤도에서 가벼움 경주

2
@LightnessRacesinOrbit-요점을 봅니다. 그러한 소급 수정은 거부해서는 안되는 유효한 구성에 대해서만 예약되므로 피해가 최소화됩니다.
StoryTeller-Unslander Monica 2009 년

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