Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make is_arithmetic<myClass>::value to be true?

Tags:

c++

templates

The idea is that I have a function that does something arithmetic to the input, so maybe something like:

#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

This works great, and computes the mean for all the number types that I put in. But lets say I then create a new class:

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

And in the definition of this class, I defined the needed operators, + and /, so they work with expected inputs. Now I want to use my mean function with my new class, but it obviously won't compile due to the static_assert. So how do I tell the compiler that my new class should satisfy is_arithmetic<foo>::value ?

It would be great if when I create the class I could give it a type that satisfies is_arithmetic, but this seems like it might cause a problem with type_traits somehow?

Or would I need to create a new test, that checks to see

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

or something like that?

I'd prefer to only have to adapt my class, rather than the function if possible, but I'm curious for a solution.

like image 693
user2386276 Avatar asked Oct 17 '14 22:10

user2386276


1 Answers

The standard library type traits, such as std::is_arithmetic, with one exception (std::common_type), are "set in stone". Attempting to specialize them causes undefined behavior. is_arithmetic tests if the type is an arithmetic type as defined by the standard; user-defined types are never arithmetic types.

You can write your own trait that tests for support for the arithmetic operators:

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

The partial specialization will match only if all four expressions are well-formed (i.e., that T supports operators +, -, *, /).

Demo.

like image 91
T.C. Avatar answered Oct 03 '22 01:10

T.C.