2014-10-17 10 views
8

Chodzi o to, że mam funkcję, która robi coś arytmetyki do wejścia, więc może coś takiego:Jak zrobić is_arithmetic <myClass> :: wartość jest prawdziwa?

#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 

Działa to doskonale, i oblicza średnią dla wszystkich typów numerycznych, że umieszczone w ale pozwala. powiedzieć, że następnie utworzyć nową klasę:

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

i w definicji tej klasy i zdefiniowane potrzebne operatory + i /, więc praca z przewidywanych nakładów. Teraz chcę użyć mojej średniej funkcji z moją nową klasą, ale oczywiście nie skompiluje się z powodu static_assert. Więc jak mogę powiedzieć kompilatorowi, że moja nowa klasa powinna zadowolić is_arithmetic<foo>::value?

Byłoby wspaniale, gdyby podczas tworzenia klasy mogłem nadać mu typ, który spełnia is_arithmetic, ale wydaje się, że może to jakoś powodować problem z type_traits?

A może trzeba utworzyć nowy test, który sprawdza

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

czy coś takiego?

Wolałbym tylko dostosować moją klasę, a nie funkcję, jeśli to możliwe, ale jestem ciekaw rozwiązania.

+0

Musisz napisać własną cechę. –

+0

@ T.C. Okay, myślałem tak samo. Czy to jest tak proste, tworząc nową 'struct' jak' is_like_number' i poprzez specyfikację szablonu, która deklaruje, że jest prawdziwa dla 'foo'? Nieważne, odpowiadasz poniżej. Dzięki – user2386276

Odpowiedz

17

Standardowe cechy biblioteki, takie jak std::is_arithmetic, z jednym wyjątkiem (std::common_type) są "osadzone w kamieniu". Próba specjalizacji powoduje niezdefiniowane zachowanie. is_arithmetic testuje, czy typ jest typem arytmetycznym zgodnie z definicją w standardzie; typy zdefiniowane przez użytkownika nigdy nie są typami arytmetycznymi.

Możesz napisać własną cechę, która testuje wsparcie dla operatorów arytmetycznych:

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

Częściowa specjalizacja będzie pasował tylko wtedy, gdy wszystkie cztery wyrażenia są dobrze uformowane (czyli, że T obsługuje operatorom +, -, *, /).

Demo.

+1

Wow, to fajna sztuczka SFINAE. – leemes

+0

Będąc cool (naprawdę), to nie działa na Visual Studio 2013 ... :(Każdy pomysł? – xtofl

+0

@xtofl VC++ nie obsługuje wyrażenia SFINAE, od którego to zależy –

2

std::is_arithmetic<T>::value jest z definicji tylko true jeśli T jest arytmetyka typu pod względem standardu C++, który jest integralną lub zmienne typu, które z kolei są podstawowe typy tylko:

Rodzaje bool, char, char16_t, char32_t , wchar_t, a liczby całkowite z podpisem i bez znaku są zbiorczo nazywane typy integralne.

Istnieją trzy zmiennoprzecinkowe typy: float, double i long double.

Powiązane problemy