ByteEater
ByteEater

Reputation: 1141

How to make `enable_if` a hard requirement

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?

Upvotes: 1

Views: 177

Answers (3)

user12002570
user12002570

Reputation: 1

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
   
} 

Upvotes: 3

Nimrod
Nimrod

Reputation: 3543

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

Upvotes: 5

Fantastic Mr Fox
Fantastic Mr Fox

Reputation: 33864

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.

Upvotes: 6

Related Questions