2014-10-17 2 views
8

Die Idee ist, dass ich eine Funktion haben, die etwas Arithmetik mit dem Eingang der Fall ist, so vielleicht so etwas wie:Wie man is_arithmetic macht <myClass> :: Wert, um wahr zu sein?

#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 

Dies funktioniert gut, und berechnet den Mittelwert für alle Zahlentypen, die ich in Führung gebracht, doch lässt. dann eine neue Klasse erstellen, sage ich:

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

und in der Definition dieser Klasse, ich die benötigten Operatoren definiert, + und /, so arbeiten sie mit erwarteten Eingaben. Jetzt möchte ich meine mittlere Funktion mit meiner neuen Klasse verwenden, aber sie wird aufgrund der static_assert offensichtlich nicht kompiliert. Wie kann ich dem Compiler mitteilen, dass meine neue Klasse is_arithmetic<foo>::value erfüllen soll?

Es wäre toll, wenn ich beim Erstellen der Klasse einen Typ geben könnte, der is_arithmetic erfüllt, aber das scheint irgendwie ein Problem mit type_traits zu verursachen?

Oder brauche ich, um einen neuen Test zu erstellen, überprüft, dass

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

oder so etwas zu sehen?

Ich würde es vorziehen, nur meine Klasse anzupassen, anstatt die Funktion, wenn möglich, aber ich bin neugierig auf eine Lösung.

+0

Sie müssen Ihr eigenes Merkmal schreiben. –

+0

@ T.C. Okay, dachte ich genauso. Ist das so einfach, ein neues 'struct' zu erstellen, wie' is_like_number' und über eine Template-Spezifikation, die es für 'foo' für wahr erklärt? Nevermind, antworten Sie es unten. Danke – user2386276

Antwort

17

Die Merkmale der Standardbibliothek, wie std::is_arithmetic, mit einer Ausnahme (std::common_type) sind "in Stein gemeißelt". Der Versuch, sie zu spezialisieren, führt zu undefiniertem Verhalten. is_arithmetic testet, ob der Typ ein arithmetischer Typ ist, wie er im Standard definiert ist; Benutzerdefinierte Typen sind niemals arithmetische Typen.

Sie können Ihre eigene Eigenschaft schreiben, die für die arithmetischen Operatoren zur Unterstützung testet:

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

Die partielle Spezialisierung nur entsprechen, wenn alle vier Ausdrücke sind gut ausgebildet (das heißt, dass T Betreiber +, -, *, / unterstützt).

Demo.

+1

Wow, das ist ein cooler SFINAE-Trick. – leemes

+0

Während es (wirklich) cool ist, scheitert es nicht an Visual Studio 2013 ... :(Irgendeine Idee? – xtofl

+0

@xtofl VC++ unterstützt nicht den Ausdruck SFINAE, von dem das abhängt. –

2

std::is_arithmetic<T>::value per Definition nur true wenn T in Bezug auf die C++ Standard-Arithmetik-Typ ist, die integral oder Fließtyp ist, die nur grundlegende Typen wiederum sind:

Typen bool, char, char16_t, char32_t , wchar_t, und die vorzeichenbehafteten und vorzeichenlosen Integertypen werden zusammen als Integraltypen bezeichnet.

Es gibt drei Gleitkomma Typen: float, double und long double.

Verwandte Themen