I'm writing a template class Foo<T>
which I only want to allow certain types of T
. I have been playing around for quite a while and now the class compiles, but in the presence of a second template non-type parameter, I couldn't figure out how to instantiate it correctly. How can I give it a default value so that I can simply call Foo<int>
and so on?
#include <iostream>
#include <utility>
#include <type_traits>
template<typename T>
struct is_foo_type {
using type = typename std::enable_if_t<
// std::is_same_v<T, vec2> ||
// std::is_same_v<T, vec3> ||
// std::is_same_v<T, vec4> ||
// std::is_same_v<T, ivec2> ||
// std::is_same_v<T, ivec3> ||
// std::is_same_v<T, ivec4> ||
// std::is_same_v<T, mat2> ||
// std::is_same_v<T, mat3> ||
// std::is_same_v<T, mat4> ||
// std::is_same_v<T, mat2x2> ||
// std::is_same_v<T, mat2x3> ||
// std::is_same_v<T, mat2x4> ||
// std::is_same_v<T, mat3x2> ||
// std::is_same_v<T, mat3x3> ||
// std::is_same_v<T, mat3x4> ||
// std::is_same_v<T, mat4x2> ||
// std::is_same_v<T, mat4x3> ||
// std::is_same_v<T, mat4x4> ||
std::is_same_v<T, int> ||
std::is_same_v<T, bool> ||
std::is_same_v<T, float> ||
std::is_same_v<T, char>
>;
};
template<typename T, typename is_foo_type<T>::type = 0>
class Foo {
public:
T _x;
Foo() = default;
Foo(const T& x) : _x(x) {};
void Increment(const T& x) { _x = x; }
};
int main() {
Foo<int> a{123}; // compiler error
// using foo_int = Foo<int>; // compiler error
// using foo_bool = Foo<bool>; // compiler error
// using foo_float = Foo<float>; // compiler error
// using foo_var = std::variant<foo_int, foo_bool, foo_float>;
// foo_var my_variant;
}
CodePudding user response:
std::enable_if_t<true>
gives you a void
type. Then you're trying to do something like
template<typename T, void = 0>
which doesn't work for an obvious reason. You can kind of fix the problem with std::enable_if_t<..., int>
.
But note that you're not doing SFINAE here. Substitution will be a hard error in your example - SFINAE works only in the immediate context.
Consider the following alternative implementation:
template<typename T>
struct is_foo_type : std::disjunction<
std::is_same<T, int>,
std::is_same<T, bool>,
std::is_same<T, float>,
std::is_same<T, char>
> {};
template<typename T, typename = std::enable_if_t<is_foo_type<T>::value>>
class Foo { ... };
and note in which context std::enable_if
is used.
In this particular case you could also use a non-type template parameter
template<typename T, std::enable_if_t<is_foo_type<T>::value, int> = 0>
class Foo { ... };
to avoid the possibility of "overriding" substitution when the second type is provided explicitly, e.g. Foo<T, void>
.
CodePudding user response:
Try adding multiple template Syntax :- template<typename T, typename V> And use it accordingly Hope it works for you