2014-10-17 2 views
8

Идея заключается в том, что у меня есть функция, которая делает что-то арифметика на вход, так что, возможно, что-то вроде:Как сделать is_arithmetic <myClass> :: значение должно быть правдой?

#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 

Это прекрасно работает, и вычисляет среднее значение для всех типов номеров, которые я ставлю в Но давайте. скажу я создаю новый класс:

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

и в определении этого класса, я определил необходимые операторы + и /, поэтому они работают с ожидаемыми входами. Теперь я хочу использовать свою среднюю функцию с моим новым классом, но она, очевидно, не будет компилироваться из-за static_assert. Итак, как мне сообщить компилятору, что мой новый класс должен удовлетворять is_arithmetic<foo>::value?

Было бы здорово, если бы я создал класс, который мог бы дать ему тип, который удовлетворяет is_arithmetic, но похоже, что это может вызвать проблему с type_traits каким-то образом?

Или мне нужно создать новый тест, который проверяет

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

или что-то подобное?

Я бы предпочел только адаптировать мой класс, а не функцию, если это возможно, но мне интересно, какое решение.

+0

Вам необходимо написать собственный отзыв. –

+0

@ T.C. Ладно, я так и думал. Это простое создание новой 'struct' like' is_like_number' и с помощью спецификации шаблона, объявляющей ее true для 'foo'? Nevermind, вы отвечаете на него ниже. Спасибо – user2386276

ответ

17

Стандартные типы типа библиотеки, такие как std::is_arithmetic, за одним исключением (std::common_type), «установлены в камне». Попытка специализироваться на них вызывает неопределенное поведение. is_arithmetic проверяет, является ли тип арифметическим типом, определенным стандартом; определяемые пользователем типы никогда не являются арифметическими типами.

Вы можете написать свой собственный признак, который проверяет для поддержки арифметических операторов:

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

Частичная специализация будет соответствовать только если все четыре выражения хорошо сформированы (то есть, что T поддерживает операторы +, -, *, /).

Demo.

+1

Ничего себе, это классный трюк SFINAE. – leemes

+0

Несмотря на то, что это классно (на самом деле), он не терпит неудачу на Visual Studio 2013 ... :(Любая идея? – xtofl

+0

@xtofl VC++ не поддерживает выражение SFINAE, от которого это зависит. –

2

std::is_arithmetic<T>::value по определению только true, если T является арифметический тип с точки зрения стандарта C++, который является неотъемлемой или плавающего типа, который, в свою очередь, являются фундаментальными типами только:

Типы bool, char, char16_t, char32_t , wchar_t, а целые типы с подписью и без знака называются целыми типами.

Есть три с плавающей точкой типов: float, double и long double.

Смежные вопросы