warum ein explizit angegebener Vorlagenparameter nicht „abgeleitet“ werden kann

Nov 19 2020

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

3 IlCapitano Nov 19 2020 at 12:48

Setzen Sie die enable_ifin 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 .

2 dfrib Nov 19 2020 at 12:57

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.

1 Deduplicator Nov 19 2020 at 12:49

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_thier intstatt voidist, es natürlich etwas nutzlos macht.

Wie andere kommentierten, ist die Verwendung von Konzepten oder zumindest requiresanstelle des zusätzlichen Vorlagenarguments der primären Vorlage viel praktischer.