명시 적으로 주어진 템플릿 매개 변수를 "추론"할 수없는 이유

Nov 19 2020

그 질문에서 오는 것 : SFINAE와 함께 열거 형 값 사용

구현하려고 시도했습니다.

enum Specifier
{
    One,
    Two,
    Three
};

template <Specifier, typename UNUSED=void>
struct Foo 
{
        void Bar(){ std::cout << "Bar default" << std::endl;}
};

template <Specifier s , typename std::enable_if<s == Specifier::Two || s == Specifier::One, int>::type>
struct Foo<s>
{
    void Bar(){ std::cout << "Bar Two" << std::endl; }
};


int main()
{
   Foo< One >().Bar();
   Foo< Two >().Bar();
}

실패 :

> main.cpp:130:8: error: template parameters not deducible in partial specialization:
  130 | struct Foo<s>
      |        ^~~~~~
   main.cpp:130:8: note:         '<anonymous>'

그 아주 간단한 예를 고치는 방법? 나는 SFINAE를 좋아한다 :-)

답변

3 IlCapitano Nov 19 2020 at 12:48

enable_ifin Foo의 템플릿 인수 목록을 넣으십시오 .

template <Specifier s>
struct Foo<s, typename std::enable_if<s == Specifier::Two || s == Specifier::One, void>::type>
//                                           same as the default type used before ^^^^

데모 .

2 dfrib Nov 19 2020 at 12:57

오류에서 알 수 있듯이 템플릿 인수는 부분 전문화에서 추론 할 수 없습니다. 귀하의 예제에서는 특수화의 템플릿 매개 변수 목록에 SFINAE 구문을 배치하려고 시도했지만 특수화 선언 의 템플릿 인수 목록 (특화되는 클래스의)으로 이동해야합니다 .

template <Specifier S>
struct Foo<S, std::enable_if_t<(S == Specifier::Two) || (S == Specifier::One)>>

귀하의 예제에 적용 (조금 정리) :

#include <iostream>
#include <type_traits>

enum class Specifier {
    One,
    Two,
    Three
};

template <Specifier, typename = void>
struct Foo {
    static void bar() { std::cout << "bar default\n"; }
};

template <Specifier S>
struct Foo<S, std::enable_if_t<(S == Specifier::Two) || (S == Specifier::One)>> {
    static void bar() { std::cout << "bar One or Two\n"; }
};

int main() {
    Foo<Specifier::One>::bar();    // bar One or Two
    Foo<Specifier::Two>::bar();    // bar One or Two
    Foo<Specifier::Three>::bar();  // bar default
}

클래스 템플릿의 기본 템플릿에서 사용되지 않는 유형 템플릿 매개 변수의 이름을 지정할 필요는 없습니다 Foo.

1 Deduplicator Nov 19 2020 at 12:49

템플릿 전문화의 템플릿 인수를 추론 할 수 없다는 것은 단순한 사실입니다.

당신이 그것을 필요로하는 것은 아닙니다.

템플릿 특수화를 변경하면됩니다.

template <Specifier s>
struct Foo<s, std::enable_if_t<s == Specifier::Two || s == Specifier::One, int>>

물론 결과 비록 std::enable_if_t여기있는 int대신 void차종이 다소 쓸모.

또한 다른 사람들이 언급했듯이 개념을 사용하거나 적어도 requires기본 템플릿의 추가 템플릿 인수 대신에 훨씬 더 편리합니다.