如何制作一个类模板来返回其任何可变参数类型是否等于第一种类型。我希望能够做到这一点:
is_same<T, A, B, C>::value; // true if T is one of A, B or C
如果
T
等于这些类型中的任何一种,则其静态 value
成员将为 true
,否则为 false
。我怎样才能做到这一点?
C++17 简洁明了:
template <class T, class... Ts>
struct is_any : std::disjunction<std::is_same<T, Ts>...> {};
还有对偶:
template <class T, class... Ts>
struct are_same : std::conjunction<std::is_same<T, Ts>...> {};
使用折叠表达式的变体:
template <class T, class... Ts>
struct is_any : std::bool_constant<(std::is_same_v<T, Ts> || ...)> {};
template <class T, class... Ts>
struct are_same : std::bool_constant<(std::is_same_v<T, Ts> && ...)> {};
或者作为 C++20 概念:
template <typename T, typename... Ts>
concept is_any = std::disjunction_v<std::is_same<T, Ts>...>;
template <typename T, typename... Ts>
concept are_same = std::conjunction_v<std::is_same<T, Ts>...>;
使用模板递归:
template<typename T, typename... Rest>
struct is_any : std::false_type {};
template<typename T, typename First>
struct is_any<T, First> : std::is_same<T, First> {};
template<typename T, typename First, typename... Rest>
struct is_any<T, First, Rest...>
: std::integral_constant<bool, std::is_same<T, First>::value || is_any<T, Rest...>::value>
{};
static_assert(is_any<int, char, double, int>::value, "error 1"); // OK
static_assert(is_any<int, char, double, short>::value, "error 2"); // error
在 C++17 中,您有一个更好的解决方案,使用模板变量和折叠表达式:
template<class T, class... Rest>
inline constexpr bool are_all_same = (std::is_same_v<T, Rest> && ...);
而且用法也比所有其他示例更简单:
are_all_same<T, A, B, C>
不
::value
,没有括号!
类似这样的事情。 首先,一个小型元编程库,因为它添加了大约 2 行来一般地执行此操作:
template<template<typename,typename>class checker, typename... Ts>
struct is_any_to_first : std::false_type {};
template<template<typename,typename>class checker, typename T0, typename T1, typename... Ts>
struct is_any_to_first<checker, T0, T1, Ts...> :
std::integral_constant< bool, checker<T0, T1>::value || is_any_to_first<checker, T0, Ts...>::value>
{};
然后是 2 行实现
is_any_same_to_first
:
template<typename... Ts>
using is_any_same_to_first = is_any_to_first< std::is_same, Ts... >;
为了完整起见,原始的
is_all
,也可能有用:
template<template<typename,typename>class checker, typename... Ts>
struct is_all : std::true_type {};
template<template<typename,typename>class checker, typename T0, typename T1, typename... Ts>
struct is_all<checker, T0, T1, Ts...> :
std::integral_constant< bool, checker<T0, T1>::value && is_all<checker, T0, Ts...>::value>
{};
template<typename... Ts>
using is_all_same = is_all< std::is_same, Ts... >;
的实例。
请注意,调用
is_any_same_to_first
任何不太明确的内容都是自找麻烦。 2/3 试图回答这个问题的人(包括我)认为 is_same<A,B,C>
是正确的,当且仅当所有三个都是同一类型!
使用宽松的 C++14 constexpr 函数,这些类型的代码更容易编写,并且编译速度也可能更快,因此您可以编写:
template <class T, class ... Candidates>
constexpr bool is_all_same() {
bool pairs[] = {std::is_same<T,Candidates>::value...};
for(bool p: pairs) if(!p) return false;
return true;
}
template <class T, class ... Candidates>
constexpr bool is_any_same() {
bool pairs[] = {std::is_same<T,Candidates>::value...};
for(bool p: pairs) if(p) return true;
return false;
}
这是因为在 C++14 constexpr 函数中可以有 for 循环。
最有效的通用版本:
自 C++11
没有依赖项(不需要
#include <type_traits>
)只有一个名称
is_same
适用于 n 类型(不需要 is_same_all
)template <typename First, typename Second, typename ... Next>
struct is_same {
template <typename A, typename B>
struct is_same_min {
enum { value = false };
};
template <typename A>
struct is_same_min<A,A> {
enum { value = true };
};
template <typename X, typename Y>
constexpr static bool check() {
return is_same_min<X,Y>::value;
};
template <typename X, typename Y, typename Z, typename ... K>
constexpr static bool check() {
return is_same_min<X,Y>::value and check<Y, Z, K...>();
};
enum { value = check<First, Second, Next...>() };
};
只需使用
is_same<T1,T2,T3...>::value
如果您已经将类型集作为参数包,则可以使用折叠表达式(在 C++17 中添加):
template<class... Ts>
... // A few lines later
if constexpr ((false || ... || std::is_same_v<T, Ts>)) {
// ...
}
注意:需要双倍的
(())
,因为内部 ()
是折叠表达式的一部分。