dlaczego parametru szablonu, który jest wyraźnie podany, nie można „wywnioskować”
Wychodząc z tego pytania: Używanie wartości wyliczenia w połączeniu z SFINAE
Próbowałem wdrożyć:
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();
}
Zawodzi z:
> main.cpp:130:8: error: template parameters not deducible in partial specialization:
130 | struct Foo<s>
| ^~~~~~
main.cpp:130:8: note: '<anonymous>'
Jak naprawić ten super prosty przykład? Lubię SFINAE :-)
Odpowiedzi
Umieścić enable_if
w Foo
„s liście argumentów szablonu:
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 .
Jak mówi nam błąd, argumentów szablonów nie można wyprowadzić z częściowej specjalizacji. W naszym przykładzie próbowałeś umieścić konstrukcję SFINAE na liście parametrów szablonu specjalizacji, ale musisz przenieść ją na listę argumentów szablonu (klasy, która jest wyspecjalizowana) deklaracji specjalizacji.
template <Specifier S>
struct Foo<S, std::enable_if_t<(S == Specifier::Two) || (S == Specifier::One)>>
Zastosowany do twojego przykładu (trochę wyczyszczony):
#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
}
Zauważ, że nie musisz nazywać nieużywanego parametru szablonu typu w podstawowym szablonie szablonu klasy Foo
.
To prosty fakt, że argumentów szablonów w specjalizacjach szablonów nie można wywnioskować.
Nie żebyś tego potrzebowała.
Po prostu zmień specjalizację szablonu:
template <Specifier s>
struct Foo<s, std::enable_if_t<s == Specifier::Two || s == Specifier::One, int>>
Chociaż oczywiście wynik std::enable_if_t
bycia tutaj int
zamiast void
czyni go nieco bezużytecznym.
Ponadto, jak komentowali inni, używanie pojęć lub przynajmniej requires
zamiast dodatkowego argumentu-szablonu z szablonu podstawowego jest znacznie wygodniejsze.