galinette
galinette

Reputation: 9340

Class template specialized for is_arithmetic types and specific types

I would like to implement a template class, with specializations for std::is_arithmetic types, as well as other specific vector classes, such as :

struct Vector { double x = 0; double y = 0; double z = 0; };

I have tried:

template<typename T, typename std::enable_if_t<std::is_arithmetic_v<T>>>
class arith { static constexpr const T zero() { return (T)0; } };

template<typename T, typename std::enable_if_t<std::is_same_v<typename T, Vector>>>
class arith { static inline Vector zero() { return Vector(); } };

This causes a "template parameter '__formal' is incompatible with the declaration, on second template

I have tried with a generic empty class, that would be specialized:

template<typename T, typename Enable = void>
class arith { };

template<typename T, typename std::enable_if_t<std::is_arithmetic_v<T>>>
class arith { static constexpr const T zero() { return (T)0; } };

template<typename T, typename std::enable_if_t<std::is_same_v<typename T, Vector>>>
class arith { static inline Vector zero() { return Vector(); } };

But in that case, both specialization fail to compile with "template parameter 'Enable' is incompatible with declaration"

I also tried full specialization for Vector class, and various other solutions ... without success. I can do it via full specialization for every type, but can't get the std::is_arithmetic version to work.

Upvotes: 1

Views: 478

Answers (2)

Jarod42
Jarod42

Reputation: 218343

Before C++20, way to go with a enabler is something like:

template<typename T, typename Enable = void>
class arith;

template<typename T>
class arith<T, std::enable_if_t<std::is_arithmetic_v<T>>>
{
    static constexpr const T zero() { return (T)0; }
};

// No need of SFINAE here: fully specialized
template<>
class arith<Vector> { static inline Vector zero() { return Vector(); } };

With C++20, we might use concept

template<typename T>
class arith;

template<typename T>
requires (std::is_arithmetic_v<T>)
class arith<T>
{
    static constexpr const T zero() { return (T)0; }
};

// No need of SFINAE here: fully specialized
template<>
class arith<Vector> { static inline Vector zero() { return Vector(); } };

Demo

Upvotes: 1

Alan
Alan

Reputation: 1

The correct syntax for doing this would be as shown below. Note when partially specializing a class template you have not used the template-id.

//------------------vvvv---->this is a non-type parameter
template<typename , auto >
class arith;

template<typename T, typename std::enable_if_t<std::is_arithmetic_v<T>> U>
//---------vvvvv------------------------------------------------------->note this 
class arith<T,U> { static constexpr const T zero() { return (T)0; } };

template<typename T, typename std::enable_if_t<std::is_same_v<T, Vector>> U>
//---------vvvvv------------------------------------------------------>note this
class arith<T,U> { static inline Vector zero() { return Vector(); } };

Working demo

Upvotes: 2

Related Questions