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 about
hana::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, "");
}