在 class 模板 T 上需要有关 SFINAE 的帮助
Need help on SFINAE on class template T
我正在编写一个模板 class Foo<T>
,我只想允许某些类型的 T
。我已经玩了很长时间,现在 class 编译了,但是在第二个模板非类型参数存在的情况下,我无法弄清楚如何正确实例化它。我怎样才能给它一个默认值,这样我就可以简单地调用 Foo<int>
等等?
#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;
}
尝试添加多个模板
语法:template<typename T, typename V>
.
并相应地使用它
std::enable_if_t<true>
给你一个 void
类型。那么你正在尝试做类似
的事情
template<typename T, void = 0>
由于显而易见的原因,它不起作用。您可以使用 std::enable_if_t<..., int>
.
解决问题
但请注意,您在这里不是在做 SFINAE。在您的示例中,替换将是一个严重错误 - SFINAE 仅适用于直接上下文。
考虑以下替代实施方式:
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 { ... };
并注意在哪个上下文中使用了 std::enable_if
。
在这种特殊情况下,您还可以使用 non-type 模板参数
template<typename T, std::enable_if_t<is_foo_type<T>::value, int> = 0>
class Foo { ... };
避免在显式提供第二种类型时“覆盖”替换的可能性,例如Foo<T, void>
.
我正在编写一个模板 class Foo<T>
,我只想允许某些类型的 T
。我已经玩了很长时间,现在 class 编译了,但是在第二个模板非类型参数存在的情况下,我无法弄清楚如何正确实例化它。我怎样才能给它一个默认值,这样我就可以简单地调用 Foo<int>
等等?
#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;
}
尝试添加多个模板
语法:template<typename T, typename V>
.
并相应地使用它
std::enable_if_t<true>
给你一个 void
类型。那么你正在尝试做类似
template<typename T, void = 0>
由于显而易见的原因,它不起作用。您可以使用 std::enable_if_t<..., int>
.
但请注意,您在这里不是在做 SFINAE。在您的示例中,替换将是一个严重错误 - SFINAE 仅适用于直接上下文。
考虑以下替代实施方式:
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 { ... };
并注意在哪个上下文中使用了 std::enable_if
。
在这种特殊情况下,您还可以使用 non-type 模板参数
template<typename T, std::enable_if_t<is_foo_type<T>::value, int> = 0>
class Foo { ... };
避免在显式提供第二种类型时“覆盖”替换的可能性,例如Foo<T, void>
.