why template parameter which is explicitely given can not be “deduced”

时光总嘲笑我的痴心妄想 提交于 2021-01-05 08:55:42

问题


Coming from that question: Using enum values in combination with SFINAE

I tried to implement:

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();
}

Fails with:

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

How to fix that super simple example? I like SFINAE :-)


回答1:


Put the enable_if in Foo's template argument list:

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 ^^^^

demo.




回答2:


As the error tells us, template arguments are not deducible in partial specialization. In your example you have tried to place the SFINAE construct in the template parameter list of the specialization, but you need to move it to the template argument list (of the class being specialized) of the specialization declaration.

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

Applied to your example (cleaned up a bit):

#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
}

Note that you needn't name the non-used type template parameter in the primary template of the class template Foo.




回答3:


It's a simple fact that template-arguments in template specializations are not deduceable.

Not that you need it.

Just change the template speialization:

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

Though of course the result of std::enable_if_t here being int instead of void makes it somewhat useless.

Also, as others commented, using concepts or at least requires instead of the extra template-argument of the primary template is much more convenient.



来源:https://stackoverflow.com/questions/64911802/why-template-parameter-which-is-explicitely-given-can-not-be-deduced

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!