2014-09-12 4 views
5

TLDR: Siehe den letzten Absatz.enable_if Typ ist nicht von einer bestimmten Vorlage Klasse

Ich habe ein operator& wie so für mehrere Template-Klassen definiert:

template <typename T> 
struct Class { 
    Class(T const &t) { } 
}; 

template <typename T_Lhs, typename T_Rhs> 
struct ClassAnd { 
    ClassAnd(T_Lhs const &lhs, T_Rhs const &rhs) { } 
}; 

template <typename T, typename T_Rhs> 
ClassAnd<Class<T>, T_Rhs> operator&(Class<T> const &lhs, T_Rhs const &rhs) { 
    return ClassAnd<Class<T>, T_Rhs>(lhs, rhs); 
} 

template <typename T0, typename T1, typename T_Rhs> 
ClassAnd<ClassAnd<T0, T1>, T_Rhs> operator&(ClassAnd<T0, T1> const &lhs, T_Rhs const &rhs) { 
    return ClassAnd<ClassAnd<T0, T1>, T_Rhs>(lhs, rhs); 
} 

int main() { 
    Class<int> a(42); 
    Class<double> b(3.14); 
    auto c = a & b; 
} 

Dies funktioniert gut.

Das Problem tritt auf, wenn ich einen Betrieb nicht aufnehmen wollen, die nur auf einer Seite oder der anderen ein und Betrieb erlaubt ist, und muss eine Instanz von ClassAndNot statt ClassAnd zurück:

template <typename T> 
struct ClassNot { 
    ClassNot(T const &t) : value(t) { } 
    T value; 
}; 

template <typename T_Lhs, typename T_Rhs> 
struct ClassAndNot { 
    ClassAndNot(T_Lhs const &lhs, T_Rhs const &rhs) { } 
}; 

template <typename T_Lhs, typename T_Rhs> 
ClassAndNot<T_Lhs, T_Rhs> operator&(T_Lhs const &lhs, ClassNot<T_Rhs> const &rhs) { 
    return ClassAndNot<T_Lhs, T_Rhs>(lhs, rhs.value); 
} 

template <typename T_Rhs> 
ClassNot<T> operator!(T_Rhs const &rhs) { 
    return ClassNot<T_Rhs>(rhs); 
} 

... 

auto c = a & !b; 

Diese führt zu einer Mehrdeutigkeit zwischen der , die eine beliebige rechte Seite nimmt, um eine ClassAnd zurückzugeben, und der , die eine ClassNot rechte Seite nimmt, um eine ClassAndNot zurückzugeben.


Frage:

Wie std::enable_if verwendet hier könnte die erste operator& wenn seine rechte Seite jeder ist von ClassNot der Typen zu deaktivieren? Gibt es etwas wie std::is_same, das wahr zurückgibt, wenn eine Seite eine Vorlageninstanz des anderen ist?

p.s. Ein vollständiges Arbeitsbeispiel finden Sie unter ideone.

Antwort

6

Sie sollten in der Lage sein, Ihr eigenes Merkmal dafür zu konstruieren:

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

template <class T> 
struct IsClassNot<ClassNot<T>> : std::true_type 
{}; 


template <typename T, typename T_Rhs> 
typename std::enable_if<!IsClassNot<T_Rhs>::value, 
ClassAnd<Class<T>, T_Rhs>>::type operator&(Class<T> const &lhs, T_Rhs const &rhs) { 
    return ClassAnd<Class<T>, T_Rhs>(lhs, rhs); 
} 

Live example


Natürlich können Sie mit Verallgemeinerungen verrückt und schafft ein universell einsetzbares Merkmal:

template <class T, template <class...> class TT> 
struct is_instantiation_of : std::false_type 
{}; 

template <template <class... > class TT, class... A> 
struct is_instantiation_of<TT<A...>, TT> : std::true_type 
{}; 

template <class T> 
using IsClassNot = is_instantiation_of<T, ClassNot>; 

Live example

+0

Ihr zweites Beispiel ist genau das, was ich suchte (aber von der Standardbibliothek bereitgestellt). Ich werde mit dem ersten Beispiel gehen, um die Dinge ein wenig einfacher zu halten. Vielen Dank! – zennehoy

+0

@zennehoy Ich vermute, dass einer der Gründe, warum es nicht von der Standardbibliothek bereitgestellt wird, ist, dass es keine Möglichkeit gibt, es allgemein für Klassenvorlagen zu schreiben, die irgendwelche Nicht-Typ- oder Vorlagenparameter verwenden. – Angew

Verwandte Themen