2017-09-04 2 views
3

Ich möchte eine Vorlage erstellen, die nur bestimmte Typparameter akzeptiert. Für alle verbleibenden Typen möchte ich eine Kompilierzeit-Fehlermeldung ausgeben. Also schreibe ich folgendesSo schränken Sie Vorlagenparameter ein

------ ------ Version 1

template <typename T_,bool isError = true> 
struct Error { 
    static_assert(!isError, "Invalid Type"); 
}; 

template <typename T_> 
struct Wrapper : Error <T_> { 
private: 
    T_ value_; 
}; 

template <> 
struct Wrapper<int> : Error<int, false> { 
private: 
    int value_; 
}; 

int main() 
{ 
    Wrapper<int> wi; 
    Wrapper<long> wl; // I get the Invalid Type. 
} 

Da ich nicht Typparameter T_ verwenden habe ich es entfernt haben und der Code funktioniert nicht mehr.

------ ------ Version 2

template <bool isError = true> 
struct Error { 
    static_assert(!isError, "Invalid Type"); 
}; 

template <typename T_> 
struct Wrapper : Error <> { 
private: 
    T_ value_; 
}; 

template <> 
struct Wrapper<int> : Error<false> { 
private: 
    int value_; 
}; 

int main() 
{ 
    Wrapper<int> wi; // I get Invalid type ????? 
    Wrapper<long> wl; // I get the Invalid Type. 
} 

Meine Fragen sind. Warum passiert das, nachdem das Argument type entfernt wurde? Ist diese Lösung "sauber"? Oder gibt es bessere Möglichkeiten, meine Absichten zu erreichen?

+1

Sie Fehler bekam auch ohne 'wi/wl'. Weil 'Error' instanziiert wird. – Jarod42

+2

Wenn Sie 'T_' entfernen, ist die Basisklasse' Error <> 'für die primäre 'Wrapper'-Vorlage nicht mehr vom Template-Parameter abhängig, sodass sie instanziiert wird, ohne' Wrapper ' selbst zu instanziieren. Wie Jarod darauf hinweist, wirst du auf den Fehler stoßen, selbst wenn du ein leeres 'main' hast. – Praetorian

Antwort

4

Sobald Sie haben:

template <typename T_> 
struct Wrapper : Error <> { 
private: 
    T_ value_; 
}; 

Wir können sehen, dass Error<> vollständig spezifiziert ist (das heißt, alle Template-Parameter bekannt), im Gegensatz zu früher, wo es war immer noch abhängig. Aus diesem Grund wird der Compiler tatsächlich fortfahren und Error<> bedingungslos instanziieren, was bedeutet, dass dieser Code niemals kompiliert wird (auch wenn Wrapper überhaupt nicht erwähnt wird). Als Error noch abhängig von T war, war es ein abhängiger Typ, also wurde es nur von Fall zu Fall instanziiert, wenn ein Wrapper<T> es brauchte.

Ich würde wahrscheinlich das Merkmal trennen ein wenig anders:

template <class T> 
struct my_trait : std::false_type {}; 

template <> 
struct my_trait<int> : std::true_type {}; 

template <class T> 
struct Wrapper { 
    static_assert(my_trait<T>::value, ""); 
}; 

int main() 
{ 
    Wrapper<int> wi; 
    Wrapper<long> wl; // I get the Invalid Type. 
} 

Wenn Sie wirklich die Fehlermeldung wieder verwenden möchten, können Sie etwas tun können:

template <typename T> 
struct Error { 
    static_assert(my_trait<T>::value, "Invalid Type"); 
}; 

template <class T> 
struct Wrapper { 
    static constexpr auto unused = Error<T>{}; 
}; 
+0

Danke. Ihr Vorschlag ist deutlich lesbarer und weniger ausführlich. –

+0

@JacintoResende Danke. Wenn Sie das Gefühl haben, dass dies Ihre Frage vollständig beantwortet, können Sie es akzeptieren, damit die Leute wissen, dass diese Frage keine weiteren Antworten benötigt. –

Verwandte Themen