2015-10-17 8 views
6

Sto cercando un typetrait "is_comparable" ma non ne trovo nessuno.Cerca "is_comparable" typetrait

È molto facile crearne uno che controlli se è stato implementato un operator== per una classe, ma questo esclude gli operatori definiti globali.

È impossibile implementare un typetait is_comparable?

risposta

3

lo prendo si intende un tratto che, per due tipi L e R e oggetti lhs e rhs di quei tipi, rispettivamente, produrrà true se l'lhs == rhs compilerà e false altrimenti. Apprezziamo che in teoria lhs == rhs potrebbe compilare anche se rhs == lhs o lhs != rhs, no.

In tal caso si potrebbe implementare il tratto come:

#include <type_traits> 

template<class ...> using void_t = void; 

template<typename L, typename R, class = void> 
struct is_comparable : std::false_type {}; 

template<typename L, typename R> 
using comparability = decltype(std::declval<L>() == std::declval<R>()); 

template<typename L, typename R> 
struct is_comparable<L,R,void_t<comparability<L,R>>> : std::true_type{}; 

Ciò si applica un modello popolare SFINAE per la definizione dei tratti che si spiega nella risposta alla this question

Alcune illustrazioni:

struct noncomparable{}; 

struct comparable_right 
{ 
    bool operator==(comparable_right const & other) const { 
     return true; 
    } 
}; 

struct any_comparable_right 
{ 
    template<typename T> 
    bool operator==(T && other) const { 
     return false; 
    } 
}; 

bool operator==(noncomparable const & lhs, int i) { 
    return true; 
} 

#include <string> 

static_assert(is_comparable<comparable_right,comparable_right>::value,""); 
static_assert(!is_comparable<noncomparable,noncomparable>::value,""); 
static_assert(!is_comparable<noncomparable,any_comparable_right>::value,""); 
static_assert(is_comparable<any_comparable_right,noncomparable>::value,""); 
static_assert(is_comparable<noncomparable,int>::value,""); 
static_assert(!is_comparable<int,noncomparable>::value,""); 
static_assert(is_comparable<char *,std::string>::value,""); 
static_assert(!is_comparable<char const *,char>::value,""); 
static_assert(is_comparable<double,char>::value,""); 

Se si desidera che il carattere richieda che l'uguaglianza sia simmetrica e quella disuguaglianza esiste anche ed è simmetrico, puoi vedere come elaborarlo tu stesso.

+0

Thx per la risposta, ma non funziona. Anche il tuo static_assert ha esito negativo durante il tentativo di compilare questo codice con gcc. Il problema sembra essere "std :: declval () == std :: declval ()" che non viene valutato. È interessante notare che clang-3.8 genera un'eccezione compilata come mi aspetterei. – Gene

+0

@Gene Odd, ha compilato per me con [gcc 5.2 live] (https://goo.gl/0Le5lw) e [clang 3.6 live] (https://goo.gl/uLkdnm). Forse potresti pubblicare la tua compilazione fallita? –

+0

Interessante ... Ho usato gcc 4.9.2 che si lamenta anche di static_assert. Anche il mio esempio locale è stato un po 'più complicato. Ho aggiunto una definizione di coppia alla fine, il che rende il clang 3.6 live anche fallire inaspettatamente: https://goo.gl/OKsuIU – Gene