클래스 전문화에 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.