C++ 两种类型/元组中的常见类型
我有两个元组——被建模为元组的类型,因此保证在它们的参数包中最多包含一次每种类型,确切地说——(比如C++ 两种类型/元组中的常见类型,c++,tuples,c++14,metaprogramming,C++,Tuples,C++14,Metaprogramming,我有两个元组——被建模为元组的类型,因此保证在它们的参数包中最多包含一次每种类型,确切地说——(比如A=std::tuple和B=std::tuple),我希望获得一个typedef,它对应于A和B交叉处的类型元组(在本例中,tuple\u intersect::type=std::tuple)。我该如何处理这个问题?这个问题分几个部分解决 在第一部分中,让我们创建一个模板类type\u search;,它确定type\u 2\u search是否是中的任何类型……所有类型 #include &
A=std::tuple
和B=std::tuple
),我希望获得一个typedef,它对应于A
和B
交叉处的类型元组(在本例中,tuple\u intersect::type=std::tuple
)。我该如何处理这个问题?这个问题分几个部分解决
在第一部分中,让我们创建一个模板类type\u search;
,它确定type\u 2\u search
是否是中的任何类型……所有类型
#include <type_traits>
#include <iostream>
#include <tuple>
template<typename type_2_search, typename ...all_types> class type_search;
template<typename type_2_search,
typename type_2_compare,
typename ...all_types> class type_compare
: public type_search<type_2_search, all_types...>
{
};
template<typename type_2_search,
typename ...all_types>
class type_compare<type_2_search, type_2_search, all_types...>
: public std::true_type {};
template<typename type_2_search>
class type_search<type_2_search> : public std::false_type {};
template<typename type_2_search, typename first_type, typename ...all_types>
class type_search<type_2_search, first_type, all_types...> :
public type_compare<type_2_search, first_type, all_types...>
{
};
int main()
{
std::cout << type_search<int, char, double, int *>::value << std::endl;
std::cout << type_search<int, int, char, double, int *>::value << std::endl;
std::cout << type_search<int, char, double, int *, int>::value << std::endl;
std::cout << type_search<int, char, int, double, int *>::value << std::endl;
}
下一部分是模板类add\u 2\u bag\u if\u type\u in\u tuple;
。第一个参数是类型。第三个参数是std::tuple
。如果第二个bool
为true
,模板将返回一个std::tuple
,它将添加该tuple的类型。否则,它将返回相同的tuple。公平吗直截了当:
template<typename type, bool value, typename tuple_bag>
class add_2_bag_if_type_in_tuple;
template<typename type, typename tuple_bag>
class add_2_bag_if_type_in_tuple<type, false, tuple_bag> {
public:
typedef tuple_bag type_t;
};
template<typename type, typename ...types>
class add_2_bag_if_type_in_tuple<type, true, std::tuple<types...>> {
public:
typedef std::tuple<type, types...> type_t;
};
对于拼图的最后一块:从第一个元组中提取第一个类型,递归使用compute\u intersection
计算第一个元组其余部分与第二个元组的交集,然后type\u search
提取的类型,如果在元组中提取类型,则“add\u 2\u bag\u”:
template<typename tuple1_type,
typename ...tuple1_types, typename ...tuple2_types>
class compute_intersection<std::tuple<tuple1_type, tuple1_types...>,
std::tuple<tuple2_types...>> {
public:
typedef typename compute_intersection<std::tuple<tuple1_types...>,
std::tuple<tuple2_types...>>
::type_t previous_bag_t;
typedef typename add_2_bag_if_type_in_tuple<
tuple1_type,
type_search<tuple1_type, tuple2_types...>::value,
previous_bag_t>::type_t type_t;
};
模板
类计算交叉{
公众:
typedef typename计算交叉点
::键入上一个包;
typedef typename如果在元组中键入,则添加2个袋子<
tuple1_类型,
键入搜索::值,
上一个包>::type\u t type\u t;
};
完整的测试程序:
#include <type_traits>
#include <iostream>
#include <tuple>
template<typename type_2_search, typename ...all_types> class type_search;
template<typename type_2_search,
typename type_2_compare,
typename ...all_types> class type_compare
: public type_search<type_2_search, all_types...>
{
};
template<typename type_2_search,
typename ...all_types>
class type_compare<type_2_search, type_2_search, all_types...>
: public std::true_type {};
template<typename type_2_search>
class type_search<type_2_search> : public std::false_type {};
template<typename type_2_search, typename first_type, typename ...all_types>
class type_search<type_2_search, first_type, all_types...> :
public type_compare<type_2_search, first_type, all_types...>
{
};
// add_2_bag_if_type_in_tuple adds the type to tuple_bag
//
// The third template parameter is a tuple_bag
//
// If the 2nd template parameter is true, add the first parameter to the
// bag of types, otherwise the bag of types is unchanged.
template<typename type, bool value, typename tuple_bag>
class add_2_bag_if_type_in_tuple;
template<typename type, typename tuple_bag>
class add_2_bag_if_type_in_tuple<type, false, tuple_bag> {
public:
typedef tuple_bag type_t;
};
template<typename type, typename ...types>
class add_2_bag_if_type_in_tuple<type, true, std::tuple<types...>> {
public:
typedef std::tuple<type, types...> type_t;
};
/////////
template<typename tuple1_types,
typename tuple2_types> class compute_intersection;
template<typename ...tuple2_types>
class compute_intersection<std::tuple<>,
std::tuple<tuple2_types...>> {
public:
typedef std::tuple<> type_t;
};
template<typename tuple1_type,
typename ...tuple1_types, typename ...tuple2_types>
class compute_intersection<std::tuple<tuple1_type, tuple1_types...>,
std::tuple<tuple2_types...>> {
public:
typedef typename compute_intersection<std::tuple<tuple1_types...>,
std::tuple<tuple2_types...>>
::type_t previous_bag_t;
typedef typename add_2_bag_if_type_in_tuple<
tuple1_type,
type_search<tuple1_type, tuple2_types...>::value,
previous_bag_t>::type_t type_t;
};
int main()
{
// Test case: no intersection
typedef compute_intersection<std::tuple<int>, std::tuple<char>>::type_t
one_type;
std::tuple<> one=one_type();
// Test case: one of the types intersect
typedef compute_intersection<std::tuple<int, char>,
std::tuple<char, double>>::type_t
two_type;
std::tuple<char> two = two_type();
// Test case, two types intersect, but in different order:
typedef compute_intersection<std::tuple<int, char, int *>,
std::tuple<int *, char, double>>::type_t
three_type;
std::tuple<char, int *> three = three_type();
}
#包括
#包括
#包括
模板类类型搜索;
模板类类型\u比较
:公共类型搜索
{
};
模板
类类型比较
:public std::true_type{};
模板
类类型_搜索:public std::false_类型{};
模板
类类型搜索:
公共类型比较
{
};
//如果tuple中的类型将类型添加到tuple\u bag,则添加2\u bag\u
//
//第三个模板参数是tuple_bag
//
//如果第二个模板参数为true,则将第一个参数添加到
//类型袋,否则类型袋不变。
模板
如果在元组中键入,则类添加\u 2\u bag\u;
模板
类添加\u 2\u包\u如果\u在\u元组中键入\u{
公众:
typedef元组\u袋类型\u t;
};
模板
类添加\u 2\u包\u如果\u在\u元组中键入\u{
公众:
typedef std::元组类型\u t;
};
/////////
模板类计算交;
模板
类计算交叉{
公众:
typedef std::元组类型\u t;
};
模板
类计算交叉{
公众:
typedef typename计算交叉点
::键入上一个包;
typedef typename如果在元组中键入,则添加2个袋子<
tuple1_类型,
键入搜索::值,
上一个包>::type\u t type\u t;
};
int main()
{
//测试用例:无交叉点
类型定义计算交点::类型
1型;
std::tuple one=one_type();
//测试用例:其中一个类型相交
类型定义计算交点::类型
双U型;
std::tuple two=two_type();
//在测试用例中,两种类型相交,但顺序不同:
类型定义计算交点::类型
三U型;
std::tuple three=three_type();
}
您可以使用随一起使用的has\u类型(从):
#包括
#包括
// ##############################################
//从https://stackoverflow.com/a/25958302/678093
模板
结构具有_类型;
模板
结构的类型为:std::false\u类型{};
模板
结构具有_类型:具有_类型{};
模板
结构的类型为:std::true\u类型{};
// ##############################################
模板
结构相交
{
模板
静态constexpr自动生成交叉点(标准::索引顺序){
返回std::tuple\u cat(
std::有条件的<
有两种类型<
std::元组元素,
S2
>::价值,
std::tuple,
std::tuple
>{}...);
}
使用type=decltype(make_交集(std::make_索引_序列{}));
};
结构T1{};
结构T2{};
结构T3{};
使用A=std::tuple;
使用B=std::tuple;
int main()
{
static_assert(std::is_samehow abouthana::intersection
?谢谢——我已经看过了,但不想添加一个hana依赖项。没有外部依赖项的东西吗?@indivibleAtom:你不需要添加依赖项就可以读取代码并查看它是如何完成的(而不是期望这里的人毫无理由地重新发明轮子).@ildjarn——我不同意你的看法。如果把你所说的限制在一定范围内,你所说的几乎适用于任何事情。帮助从复杂的机器中提取轮子的本质,似乎是一个值得提出的问题,而且与StackOverflow平台相关。好吧,一个懒惰的问题可以给出有用的答案,是的;但这并不是一个好问题(我说“我知道有代码可以完全满足我的要求,但我拒绝阅读它”就构成了懒惰)。;-]非常感谢你给出了非常详细的答案,山姆。我不愿意把这个标记为接受(我很乐意),但我非常喜欢m.s.简洁的回答。抱歉。顺便说一句,我更喜欢关于类型包含的第二个答案,因为它是非递归的。PS-我也没有足够的代表来支持--aargh@indivisibleatom:你现在知道了
template<typename tuple1_type,
typename ...tuple1_types, typename ...tuple2_types>
class compute_intersection<std::tuple<tuple1_type, tuple1_types...>,
std::tuple<tuple2_types...>> {
public:
typedef typename compute_intersection<std::tuple<tuple1_types...>,
std::tuple<tuple2_types...>>
::type_t previous_bag_t;
typedef typename add_2_bag_if_type_in_tuple<
tuple1_type,
type_search<tuple1_type, tuple2_types...>::value,
previous_bag_t>::type_t type_t;
};
#include <type_traits>
#include <iostream>
#include <tuple>
template<typename type_2_search, typename ...all_types> class type_search;
template<typename type_2_search,
typename type_2_compare,
typename ...all_types> class type_compare
: public type_search<type_2_search, all_types...>
{
};
template<typename type_2_search,
typename ...all_types>
class type_compare<type_2_search, type_2_search, all_types...>
: public std::true_type {};
template<typename type_2_search>
class type_search<type_2_search> : public std::false_type {};
template<typename type_2_search, typename first_type, typename ...all_types>
class type_search<type_2_search, first_type, all_types...> :
public type_compare<type_2_search, first_type, all_types...>
{
};
// add_2_bag_if_type_in_tuple adds the type to tuple_bag
//
// The third template parameter is a tuple_bag
//
// If the 2nd template parameter is true, add the first parameter to the
// bag of types, otherwise the bag of types is unchanged.
template<typename type, bool value, typename tuple_bag>
class add_2_bag_if_type_in_tuple;
template<typename type, typename tuple_bag>
class add_2_bag_if_type_in_tuple<type, false, tuple_bag> {
public:
typedef tuple_bag type_t;
};
template<typename type, typename ...types>
class add_2_bag_if_type_in_tuple<type, true, std::tuple<types...>> {
public:
typedef std::tuple<type, types...> type_t;
};
/////////
template<typename tuple1_types,
typename tuple2_types> class compute_intersection;
template<typename ...tuple2_types>
class compute_intersection<std::tuple<>,
std::tuple<tuple2_types...>> {
public:
typedef std::tuple<> type_t;
};
template<typename tuple1_type,
typename ...tuple1_types, typename ...tuple2_types>
class compute_intersection<std::tuple<tuple1_type, tuple1_types...>,
std::tuple<tuple2_types...>> {
public:
typedef typename compute_intersection<std::tuple<tuple1_types...>,
std::tuple<tuple2_types...>>
::type_t previous_bag_t;
typedef typename add_2_bag_if_type_in_tuple<
tuple1_type,
type_search<tuple1_type, tuple2_types...>::value,
previous_bag_t>::type_t type_t;
};
int main()
{
// Test case: no intersection
typedef compute_intersection<std::tuple<int>, std::tuple<char>>::type_t
one_type;
std::tuple<> one=one_type();
// Test case: one of the types intersect
typedef compute_intersection<std::tuple<int, char>,
std::tuple<char, double>>::type_t
two_type;
std::tuple<char> two = two_type();
// Test case, two types intersect, but in different order:
typedef compute_intersection<std::tuple<int, char, int *>,
std::tuple<int *, char, double>>::type_t
three_type;
std::tuple<char, int *> three = three_type();
}
#include <tuple>
#include <type_traits>
// ##############################################
// from https://stackoverflow.com/a/25958302/678093
template <typename T, typename Tuple>
struct has_type;
template <typename T>
struct has_type<T, std::tuple<>> : std::false_type {};
template <typename T, typename U, typename... Ts>
struct has_type<T, std::tuple<U, Ts...>> : has_type<T, std::tuple<Ts...>> {};
template <typename T, typename... Ts>
struct has_type<T, std::tuple<T, Ts...>> : std::true_type {};
// ##############################################
template <typename S1, typename S2>
struct intersect
{
template <std::size_t... Indices>
static constexpr auto make_intersection(std::index_sequence<Indices...> ) {
return std::tuple_cat(
std::conditional_t<
has_type<
std::tuple_element_t<Indices, S1>,
S2
>::value,
std::tuple<std::tuple_element_t<Indices, S1>>,
std::tuple<>
>{}...);
}
using type = decltype(make_intersection(std::make_index_sequence<std::tuple_size<S1>::value>{}));
};
struct T1{};
struct T2{};
struct T3{};
using A = std::tuple<T1, T2>;
using B = std::tuple<T2, T3>;
int main()
{
static_assert(std::is_same<std::tuple<T2>, intersect<A, B>::type>::value, "");
}