问题
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