1

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.

galinette
  • 8,896
  • 2
  • 36
  • 87

2 Answers2

2

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

Jason
  • 36,170
  • 5
  • 26
  • 60
  • Thanks! Holy crap, the 'auto' in the main template is voodoo. I have no idea how this is understood by the compiler. – galinette Apr 06 '23 at 14:20
  • @galinette You're welcome. C++17 allows use of `auto` in non type template parameter. More information [here](https://stackoverflow.com/questions/38026884/advantages-of-auto-in-template-parameters-in-c17). – Jason Apr 06 '23 at 14:32
1

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

Jarod42
  • 203,559
  • 14
  • 181
  • 302