2014-09-12 10 views
5

TLDR: vedere l'ultimo paragrafo.enable_if type non è di una determinata classe template

Ho un operator& definiti per diverse classi template in questo modo:

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; 
} 

Questo funziona bene.

Il problema si verifica quando voglio aggiungere un non funzionamento, che è consentito solo su un lato o l'altro di una e di funzionamento, e deve restituire un'istanza di ClassAndNot piuttosto che ClassAnd:

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; 

Questo determina un'ambiguità tra lo operator& prendendo un lato arbitrario a destra per restituire un ClassAnd e lo operator& prendendo un ClassNot lato destro per restituire un ClassAndNot.


Domanda:

Come potrebbe std::enable_if essere utilizzato qui per disattivare il primo operator& se il suo lato destro è di uno qualsiasi dei tipi ClassNot? C'è qualcosa come std::is_same che restituisce true se un lato è un'istanza di template dell'altro?

p.s. È possibile trovare un esempio funzionante completo su ideone.

risposta

6

Si dovrebbe essere in grado di costruire il proprio tratto per questo:

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


Naturalmente, si può impazzire con generalizzazioni e creare un trait per tutti gli usi:

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

Il secondo esempio è esattamente quello che stavo cercando (ma fornito dalla libreria standard). Vado con il primo esempio per mantenere le cose un po 'più semplici. Grazie! – zennehoy

+0

@zennehoy Direi che uno dei motivi per cui non è fornito dalla libreria standard è che non esiste un modo per scriverlo completamente in generale per i modelli di classe che accettano parametri di modello non di modello o modello. – Angew

Problemi correlati