如何检查类型 T 是否在参数包 Ts 中
How can I check type T is among parameter pack Ts...?
我想写一个函数来返回 true,如果T
是Ts...
之一
template<class T, class... Ts>
bool is_one_of<T, Ts...>();
例如,is_one_of<int, double, int, float>
返回true
,is_one_of<int, double, std::string, bool, bool>
返回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...>();
}
}
这个检查对我来说似乎很常见,所以我想知道标准库中是否已经有这样的函数。
在您自己的实现中,一个问题是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>...>;
找到匹配类型后,不会实例化其余模板。 相反,折叠表达式实例化所有这些。 这可能会在编译时间上产生重大差异,具体取决于您的用例。
检查类型 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
值。
其他答案显示了几个正确的解决方案,以简洁明了的方式解决这个特定问题。下面是不建议针对此特定问题的解决方案,但演示了另一种技术:在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。
相关文章:
- 是否有C++编译器选项允许激进地删除所有函数调用,并将参数传递给具有空体的函数
- 是否可以对零模板参数进行模板专门化
- 函数作为模板参数,是否对返回类型强制约束
- visual是否可以在c++中创建一个接收无限数量相同类型(或至少相当数量)参数的函数
- 函数是否可以访问传递给main()的参数
- 在C++中,使用带有 std::optional 参数的函数<T>来表示可选参数是否有意义?
- 如何检查给定的参数是否为 cv::noArray()?
- 表达式 SFINAE:如何根据类型是否包含具有一个或多个参数的函数来选择模板版本
- 如果返回 -1,时间() 的参数是否被修改?
- 用于检查值是否为其任何参数的帮助程序函数
- 将类型声明为类型模板参数的模板参数的一部分是否合法?
- 模板化检查是否存在带有参数列表的类成员函数?
- 我如何知道作为参数的size_t在函数中是否有效?
- 是否可以在C++中有一个"generic"模板参数,该参数可以是非类型模板参数或类型?
- 是否可以就地构造一个固定大小的数组作为函数参数?
- C++方法是否可以根据传递给构造函数的参数具有不同的返回类型?
- 是否可以在运行时强制转换模板参数?
- 是否可以在不填充自己的参数的情况下将模板函数作为参数传递?
- 编译器是否强制根据模板参数计算表达式?
- C++中大多数/所有 setter 函数的参数是否应该写为常量引用?