Class template for numeric types
I found the error messages received from the template<typename T, typename = ...>
approach highly cryptic (VS 2015), but found that a static_assert
with the same type trait also works and lets me specify an error message:
#include <type_traits>
template <typename NumericType>
struct S
{
static_assert(std::is_arithmetic<NumericType>::value, "NumericType must be numeric");
};
template <typename NumericType>
NumericType add_one(NumericType n)
{
static_assert(std::is_arithmetic<NumericType>::value, "NumericType must be numeric");
return n + 1;
}
int main()
{
S<int> i;
S<char*> s; //doesn't compile
add_one(1.f);
add_one("hi there"); //doesn't compile
}
You can use the std::is_arithmetic
type trait. If you want to only enable instantiation of a class with such a type, use it in conjunction with std::enable_if
:
#include <type_traits>
template<
typename T, //real type
typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type
> struct S{};
int main() {
S<int> s; //compiles
S<char*> s; //doesn't compile
}
For a version of enable_if
that's easier to use, and a free addition of disable_if
, I highly recommend reading this wonderful article on the matter.
In C++, the technique described above has a name called "Substitution Failure Is Not An Error" (most use the acronym SFINAE). You can read more about this C++ technique on wikipedia or cppreference.com.
As of C++20, concepts make this much easier and don't spoil the interface:
#include <concepts>
template<typename T>
concept arithmetic = std::integral<T> or std::floating_point<T>;
template<typename T>
requires arithmetic<T>
struct S{};
// Shorthand: template<arithmetic T> struct S {};
Do note that there are many user types meant to be used arithmetically as well, though, so a more general concept that covers the operations you're looking for instead of the types you're looking for would be preferable in a generic interface.