warum ein explizit angegebener Vorlagenparameter nicht „abgeleitet“ werden kann
Aus dieser Frage: Verwendung von Enum-Werten in Kombination mit SFINAE
Ich habe versucht zu implementieren:
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();
}
Schlägt fehl mit:
> main.cpp:130:8: error: template parameters not deducible in partial specialization:
130 | struct Foo<s>
| ^~~~~~
main.cpp:130:8: note: '<anonymous>'
Wie kann man dieses supereinfache Beispiel beheben? Ich mag SFINAE :-)
Antworten
Setzen Sie die enable_if
in Foo
‚s - Vorlage Argumentliste:
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 .
Wie der Fehler zeigt, können Vorlagenargumente bei teilweiser Spezialisierung nicht abgeleitet werden. In Ihrem Beispiel haben Sie versucht , das SFINAE Konstrukt in der Vorlage zu platzieren Parameterliste der Spezialisierung, aber Sie müssen es auf die Vorlage bewegen Argumente Liste (von der Klasse Wesen spezialisiert) der Spezialisierung Erklärung.
template <Specifier S>
struct Foo<S, std::enable_if_t<(S == Specifier::Two) || (S == Specifier::One)>>
Auf Ihr Beispiel angewendet (etwas aufgeräumt):
#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
}
Beachten Sie, dass Sie den nicht verwendeten Typvorlagenparameter nicht in der primären Vorlage der Klassenvorlage benennen müssen Foo
.
Es ist eine einfache Tatsache, dass Vorlagenargumente in Vorlagenspezialisierungen nicht ableitbar sind.
Nicht dass du es brauchst.
Ändern Sie einfach die Spezialisierung der Vorlage:
template <Specifier s>
struct Foo<s, std::enable_if_t<s == Specifier::Two || s == Specifier::One, int>>
Obwohl das Ergebnis, dass std::enable_if_t
hier int
statt void
ist, es natürlich etwas nutzlos macht.
Wie andere kommentierten, ist die Verwendung von Konzepten oder zumindest requires
anstelle des zusätzlichen Vorlagenarguments der primären Vorlage viel praktischer.