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{};
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
}