클래스 전문화에 clang / gcc 불일치


9

전문하는 동안 나는이 문제를 건너 온 tuple_size/ tuple_element구조 바인딩 (17) C ++에서 사용자 정의 클래스.

아래 코드는 GCC에서는 컴파일되지만 clang에서는 컴파일되지 않습니다 (두 트렁크 버전 모두 아래 링크 참조).

#include <type_traits>

template<typename T, typename... Ts>
using sfinae_t = T;

template<typename T, bool... Bs>
using sfinae_v_t = sfinae_t<T, typename std::enable_if<Bs>::type...>;

template <typename T>
struct Test;

template <typename T>
struct Test<sfinae_v_t<T, std::is_integral_v<T>>> {};

void f() {
    Test<int> t;
}

https://godbolt.org/z/ztuRSq

이것은 clang에서 제공하는 오류입니다.

<source>:13:8: error: class template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list

struct Test<sfinae_v_t<T, std::is_integral<T>::value>> {};

       ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1 error generated.

Compiler returned: 1

이것은 컴파일러의 버그입니까, 아니면 위의 코드가 일부 UB를 호출합니까?


3
이것은 훨씬 더 단순화 될 수 있습니다 .
— EVG

3
ICC와 MSVC 모두 컴파일되지 않습니다.
— ChrisMM

@Evg 이것을gcc 컴파일하지 않는 것을 본다는 것은 놀라운 일입니다 .
— Max Langhof

1
나는 (그 같은 이유로 완전히 틀리지 않는 경우 FWIW이 잘못 형성해야 이 잘못 형성된다).
— Max Langhof

1
우리는 표준을 인용하고 있기 때문에 언어 변호사 태그를 추가했습니다.
— 기 illa Racicot

답변:


3

아래에서 ( OLD POST 아래에서) 말하는 것은 어느 정도 사실이어야하지만, 실제 문제는 SFINAE가 잘못 사용되어 더 이상 이것이 gcc의 버그인지 확실하지 않습니다.

별칭 선언은 클래스 나 함수 선언이나 전문화가 아니기 때문에 항상 성공해야합니다. 별칭을 특수화 할 수 없기 때문에 의미가 있습니다. 별명 선언에 실패하면 프로그램이 잘못 구성됩니다. 따라서 컴파일러는 이러한 템플릿을 인스턴스화하도록 강제 실행하기 전까지는 별칭 선언이 성공하지 못할 것이라고 가정 할 수 있습니다.

따라서 컴파일러가 프로그램이 잘못 형성되지 않을 때 발생 하기 때문에 컴파일러 sfinae_v_t<T,...>가 항상 이라고 생각하는 것은 완벽하게 허용 T됩니다. 따라서 프로그램이 잘못 구성되지 않은 모든 경우에 부분 전문화가 전문화되지 않아서 이것이 잘못 구성되었음을 알 수 있습니다. (그게 clang이하는 일입니다).

컴파일러 가이 작업을 수행해야한다고 생각하지 않습니다. 그리고 그것이 "아니오, sfinae_v_t어떤 유형이든, 어떤 것이 든 "이라고 생각하지 않는다면, 이것이 재 선언이라는 것이 분명하지 않습니다. 따라서 그중 하나를 인스턴스화 할 때까지 오류가 발생하지 않는 것은 아무 문제가 없다고 생각합니다.

그러나 인스턴스화 할 때 std::enable_if템플릿 선언에 따라 다시 선언하거나 프로그램으로 인해 형식이 잘못되었다는 문제가 있어야합니다 . GCC는 그중 하나 이상을 선택해야하지만 둘 중 하나는 선택하지 않아야합니다.

이것이없는 더 쉬운 예제에는 절대 적용되지 않습니다 std::enable_if. 그래서 나는 이것이 GCC의 버그라고 생각하지만, 더 이상 확실하게 말할 수 없다는 것을 충분히 염두에 두었습니다. 나는 단지 누군가 그것을 버그로보고하고 gcc 사람들이 그것에 대해 생각하도록해야합니다.

오래된 포스트

이것은 gcc의 버그입니다. 표준은 함수 템플릿에서 클래스 템플릿을 변환하기위한 규칙 을 제공합니다 . 하나의 클래스 템플릿이 다른 함수보다 부분 함수 템플릿 순서에서 우선하는 경우 다른 클래스 템플릿보다 더 전문화됩니다.

여기 에 함수를 만들었고 gcc는 호출하는 것이 모호하다고 주장하므로 클래스 템플릿도 동일하게 지정해야합니다.

참고 : 표준을주의 깊게 읽으면 내 머리 속에있는 컴파일러는 clang에 동의합니다.


인가 sfinae_v_t<T, std::is_integral_v<T>>와 sfinae_v_t<T, !std::is_integral_v<T>>같은 종류로 취급? 의미 상으로는 그렇지 않습니다.
— ofo

@GuillaumeRacicot 아마도 가능하지만 정확히 왜 그런지 이해하고 싶습니다. 예를 들어, 표준은 말한다 "종속 이름이 부분 특수화를 선언 할 때 확인할 수 없습니다, 그러나 부분 특수화로 대체 할 때 확인됩니다." 하지 않습니다 그들은 동일한 유형의 이후 부분 특수화에 T를 대체 한 후 결정하는 것을 의미인지 있음 sfinae_v_t<T>에 따라 달라집니다 T? 어떤 경우에는 둘 중 하나가 잘못 형성되기 때문에 동일하지 않습니다.
— ofo

@ofo 확실하지 않습니다. 이 두 가지 중 하나는 유형이 아니며 템플릿이 아닌 컨텍스트에서 두 가지를 모두 사용하면 컴파일 오류가 발생하기 때문에 두 가지에 대해 생각하는 것은 약간의 생각 enable_if_t입니다. 표준에 대한 나의 가장 좋은 읽은 것은 그것이 같은지 아닌지는 중요하지 않다는 것입니다. 부분 순서의 경우 항상 한 함수의 templare 매개 변수 형식을 다른 함수의 템플릿 인수 형식 int과 비교 한 다음 (즉, 이미 대체 됨) 그 중 하나에 실제 형식이 있으므로 비교할 필요가 없습니다. 그것들은 추상적입니다.
— n314159

1
더 깊이 파고, 나는 발견 이 에서 여기 . SFINAE는 템플릿 별칭과 함께 template<bool B, typename T> enable_if_t = typename enable_if<B, T>::type;잘 작동해야합니다. 그렇지 않으면 작동하지 않습니다. 계속해서 gcc에 대해 버그를 제기하지만 gcc가 잘못되었는지 확실하지 않습니다. 감사.
— ofo
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.