我如何检查类型 T 是否在参数包 Ts 中...?
How can I check type T is among parameter pack Ts...?
如果 T
是 Ts...
之一,我想写一个函数 return true
template<class T, class... Ts>
bool is_one_of<T, Ts...>();
例如,is_one_of<int, double, int, float>
returns true
,以及 is_one_of<int, double, std::string, bool, bool>
returns false
.
我自己的实现是
template<class T1, class T2>
bool is_one_of<T1, T2>() {
return std::is_same<T1, T2>;
}
template<class T1, class T2, class... Ts>
bool is_one_of<T1, T2, Ts...>() {
if (std::is_same<T1, T2>) {
return true;
}
else {
return is_one_of<T1, Ts...>();
}
}
这个检查对我来说似乎很常见,所以我想知道标准库中是否已经有这样的函数。
检查类型 T 是否在参数包 Ts 中:
template<class T0, class... Ts>
constexpr bool is_one_of = (std::is_same<T0, Ts>{}||...);
模板变量。
选择:
template<class T0, class... Ts>
constexpr std::integral_constant<bool,(std::is_same<T0, Ts>{}||...)> is_one_of = {};
其中有细微差别;它的类型带有它的值并且它是无状态的,而不是 constexpr bool
值。
在您自己的实现中,一个问题是 C++ 不允许对函数模板进行部分特化。
您可以使用折叠表达式(在 C++17 中引入)代替递归函数调用。
template<class T1, class... Ts>
constexpr bool is_one_of() noexcept {
return (std::is_same_v<T1, Ts> || ...);
}
如果您使用的是折叠表达式和 std::disjunction
不可用的 C++11,您可以像这样实现 is_one_of
:
template<class...> struct is_one_of: std::false_type {};
template<class T1, class T2> struct is_one_of<T1, T2>: std::is_same<T1, T2> {};
template<class T1, class T2, class... Ts> struct is_one_of<T1, T2, Ts...>: std::conditional<std::is_same<T1, T2>::value, std::is_same<T1, T2>, is_one_of<T1, Ts...>>::type {};
您也可以使用std::disjunction
来避免不必要的模板实例化:
template <class T0, class... Ts>
constexpr bool is_one_of = std::disjunction_v<std::is_same<T0, Ts>...>;
找到匹配类型后,其余模板不实例化。相反,折叠表达式实例化所有这些。根据您的用例,这可能会在编译时间上产生显着差异。
其他答案显示了几个正确的解决方案,以简洁明了的方式解决了这个特定问题。这是一个 不推荐用于此特定问题的解决方案 ,但演示了另一种技术:在 constexpr
函数中,您可以使用简单的 for 循环和简单的逻辑来计算结果在编译时。这允许摆脱 OP 代码的递归和尝试的部分模板专业化。
#include <initializer_list>
#include <type_traits>
template<class T, class... Ts>
constexpr bool is_one_of() {
bool ret = false;
for(bool is_this_one : {std::is_same<T, Ts>::value...}) {
ret |= is_this_one;// alternative style: `if(is_this_one) return true;`
}
return ret;
}
static_assert(is_one_of<int, double, int, float>(), "");
static_assert(!is_one_of<int, double, char, bool, bool>(), "");
至少需要 C++14.
如果 T
是 Ts...
template<class T, class... Ts>
bool is_one_of<T, Ts...>();
例如,is_one_of<int, double, int, float>
returns true
,以及 is_one_of<int, double, std::string, bool, bool>
returns false
.
我自己的实现是
template<class T1, class T2>
bool is_one_of<T1, T2>() {
return std::is_same<T1, T2>;
}
template<class T1, class T2, class... Ts>
bool is_one_of<T1, T2, Ts...>() {
if (std::is_same<T1, T2>) {
return true;
}
else {
return is_one_of<T1, Ts...>();
}
}
这个检查对我来说似乎很常见,所以我想知道标准库中是否已经有这样的函数。
检查类型 T 是否在参数包 Ts 中:
template<class T0, class... Ts>
constexpr bool is_one_of = (std::is_same<T0, Ts>{}||...);
模板变量。
选择:
template<class T0, class... Ts>
constexpr std::integral_constant<bool,(std::is_same<T0, Ts>{}||...)> is_one_of = {};
其中有细微差别;它的类型带有它的值并且它是无状态的,而不是 constexpr bool
值。
在您自己的实现中,一个问题是 C++ 不允许对函数模板进行部分特化。
您可以使用折叠表达式(在 C++17 中引入)代替递归函数调用。
template<class T1, class... Ts>
constexpr bool is_one_of() noexcept {
return (std::is_same_v<T1, Ts> || ...);
}
如果您使用的是折叠表达式和 std::disjunction
不可用的 C++11,您可以像这样实现 is_one_of
:
template<class...> struct is_one_of: std::false_type {};
template<class T1, class T2> struct is_one_of<T1, T2>: std::is_same<T1, T2> {};
template<class T1, class T2, class... Ts> struct is_one_of<T1, T2, Ts...>: std::conditional<std::is_same<T1, T2>::value, std::is_same<T1, T2>, is_one_of<T1, Ts...>>::type {};
您也可以使用std::disjunction
来避免不必要的模板实例化:
template <class T0, class... Ts>
constexpr bool is_one_of = std::disjunction_v<std::is_same<T0, Ts>...>;
找到匹配类型后,其余模板不实例化。相反,折叠表达式实例化所有这些。根据您的用例,这可能会在编译时间上产生显着差异。
其他答案显示了几个正确的解决方案,以简洁明了的方式解决了这个特定问题。这是一个 不推荐用于此特定问题的解决方案 ,但演示了另一种技术:在 constexpr
函数中,您可以使用简单的 for 循环和简单的逻辑来计算结果在编译时。这允许摆脱 OP 代码的递归和尝试的部分模板专业化。
#include <initializer_list>
#include <type_traits>
template<class T, class... Ts>
constexpr bool is_one_of() {
bool ret = false;
for(bool is_this_one : {std::is_same<T, Ts>::value...}) {
ret |= is_this_one;// alternative style: `if(is_this_one) return true;`
}
return ret;
}
static_assert(is_one_of<int, double, int, float>(), "");
static_assert(!is_one_of<int, double, char, bool, bool>(), "");
至少需要 C++14.