Home > Blockchain >  How to make `enable_if` a hard requirement
How to make `enable_if` a hard requirement

Time:11-29

This answer contains the following code:

#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
}

The requirement that T satisfy is_arithmetic can easily be defeated, though, by specifying an arbitrary second type argument for the template S, e.g. S<char*, void>. Is there a way to foreclose this possibility?

CodePudding user response:

Use concept will be much easier (since you have mentioned),

template <typename T>
concept Arithmetic = std::is_arithmetic_v<T>;

template<Arithmetic T> struct S{};

Demo

CodePudding user response:

The requirement that T satisfy is_arithmetic can easily be defeated

I mean, it is SFINAE, aka substitution is not an error. If you want to force specific types in templates, you can use concepts in c 20, or in c 17 - c 11, you have static_assert:

template<
    typename T //real type
> struct S{
    static_assert(std::is_arithmetic_v<T>, "T must be arithmetic");
};

There is no defeating that.

CodePudding user response:

Is there a way to foreclose this possibility?

Yes, there is as shown below. In particular, we can make the second parameter a non-type parameter with a default.

template<
    typename T,
    //make the second parameter a non-type parameter with default 
    typename std::enable_if<std::is_arithmetic<T>::value, nullptr_t>::type N = nullptr 
> struct S{};

int main() {
   S<int> s; //compiles 
    //S<int, void> S2;  //DOESN'T COMPILE 
   //S<int, 1> S3;     //DOESN'T COMPILE
   
} 
  • Related