2014-10-17 10 views
8

L'idea è che ho una funzione che fa qualcosa l'aritmetica con l'ingresso, quindi forse qualcosa di simile:Come rendere is_arithmetic <myClass> :: valore vero?

#include <type_traits> 
#include <vector> 

using namespace std; 

template<typename T> 
double mean(const vector<T>& vec) 
{ 
    static_assert(is_arithmetic<T>::value, "Arithmetic not possible on this type"); 
    //compute mean (average) 
}//mean 

Questa grande opera, e calcola la media per tutti i tipi di numero che ho messo in Ma lascia. dico allora creo una nuova classe:

class foo 
{ 
    // class that has arithmetic operations created 
};// foo 

e nella definizione di questa classe, ho definito gli operatori necessari, + e /, in modo da lavorare con ingressi attesi. Ora voglio usare la mia funzione media con la mia nuova classe, ma ovviamente non verrà compilata a causa di static_assert. Quindi, come faccio a dire al compilatore che la mia nuova classe dovrebbe soddisfare is_arithmetic<foo>::value?

Sarebbe bello se quando creo la classe potrei dargli un tipo che soddisfi is_arithmetic, ma questo sembra che potrebbe causare un problema con type_traits in qualche modo?

O avrei bisogno di creare un nuovo test, che verifica

is_arithmetic<T>::value || type(T,foo) 

o qualcosa del genere?

Preferirei solo adattare la mia classe, piuttosto che la funzione se possibile, ma sono curioso di trovare una soluzione.

+0

È necessario scrivere il proprio tratto. –

+0

@ T.C. Ok, ho pensato tanto. È così semplice creare una nuova 'struct' come' is_like_number' e tramite specifiche del template che lo dichiarano vero per 'foo'? Non importa, tu rispondi sotto. Grazie – user2386276

risposta

17

I tratti di tipo di libreria standard, ad esempio std::is_arithmetic, con un'eccezione (std::common_type), sono "impostati su pietra". Il tentativo di specializzarli causa un comportamento indefinito. is_arithmetic test se il tipo è un tipo aritmetico come definito dallo standard; i tipi definiti dall'utente non sono mai tipi aritmetici.

È possibile scrivere il proprio tratto che mette alla prova per il supporto per gli operatori aritmetici:

template<class...> struct voidify { using type = void; }; 
template<class... Ts> using void_t = typename voidify<Ts...>::type; 

template<class T, class = void> 
struct supports_arithmetic_operations : std::false_type {}; 

template<class T> 
struct supports_arithmetic_operations<T, 
      void_t<decltype(std::declval<T>() + std::declval<T>()), 
        decltype(std::declval<T>() - std::declval<T>()), 
        decltype(std::declval<T>() * std::declval<T>()), 
        decltype(std::declval<T>()/std::declval<T>())>> 
     : std::true_type {}; 

La specializzazione parziale corrisponderà solo se tutte e quattro le espressioni sono ben formate (vale a dire, che T supporta gli operatori +, -, *, /).

Demo.

+1

Wow, questo è un bel trucco SFINAE. – leemes

+0

Pur essendo bello (davvero), non ha esito negativo su Visual Studio 2013 ... :(Qualche idea? – xtofl

+0

@xtofl VC++ non supporta l'espressione SFINAE, da cui dipende. –

2

std::is_arithmetic<T>::value è per definizione, true se T è tipo aritmetico in termini di C++ standard, che è solidale o tipo flottante, che a loro volta sono tipi fondamentali: l'

Tipi bool, char, char16_t, char32_t , wchar_t ei tipi interi con segno e senza segno sono chiamati collettivamente tipi integrali.

Ci sono tre virgola mobile tipi: float, double e long double.

Problemi correlati