Clang은 코드를 컴파일하지 않지만 gcc 및 msvc는 코드를 컴파일했습니다. : std::true_type {}; int

내 코드 또는 컴파일러 (가능하지 않은)에서 문제가 무엇인지 이해하지 못합니다. 다음과 같은 코드가 있습니다.

#include <iostream>
#include <type_traits>
#include <set>


template<typename T, typename = void>
struct TestA: std::false_type {};

template<typename T>
struct TestA<T, std::void_t<typename T::reverse_iterator>> : std::true_type {};

template<typename T>
struct TestA<T, std::void_t<typename T::dummy_iterator>> : std::true_type {};

int main()
{
    std::cout << TestA<std::set<int>>::value;
}

GCC와 MSVC 모두 컴파일합니다. 다른 버전의 GCC와 MSVC 17 (local) 및 19를 사용하여 godbolt에서 테스트했습니다. 다음 링크는 https://godbolt.org/z/Enfm6L 입니다.

그러나 Clang은 컴파일하지 않고 오류를 발생시킵니다.

redefinition of `'TestA<T, std::void_t<typename T::dummy_iterator> >'`

그리고 관심이 있습니다.이 코드 조각이 틀리거나 다른 것이 표준의 일부일 수 있습니다.



답변

이것은 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와 같거나 대체 실패입니까?

이 문제는 해결 된 이후의 결함이지만, 사용한 Clang 버전이 아직 수정 사항을 구현하지 않은 경우에도 두 번째 인수를 단순히로 정의 void하고 전체 대체 실패를 수행하지 않는 것으로 두 전문화를 여전히 고려할 수 있습니다 . 해결 방법은 일반 별칭을 사용하지 std::void_t않고 약간 더 복잡한 버전을 사용하는 것입니다.

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

별명을 나타내는 클래스 템플릿의 경우 대체 실패가 정의됩니다. 예제에 연결하면 Clang https://godbolt.org/z/VnkwsM이 완화 됩니다 .