【问题标题】:Common types in two TypeSets / Tuples两个 TypeSets / Tuples 中的常见类型
【发布时间】:2017-05-03 04:32:13
【问题描述】:

我有两个元组——TypeSets 被建模为元组,因此保证在它们的参数包中最多包含每个类型一次,准确地说——(比如A = std::tuple<T1, T2>B = std::tuple<T2, T3>),我希望获得一个 typedef,对应于 AB 的交集中的类型元组(在本例中为 tuple_intersect<A,B>::type = std::tuple<T2>)。我该怎么办?

【问题讨论】:

  • 谢谢——我看过这个,但不想添加 hana 依赖项。任何没有外部依赖的东西?
  • @indivisibleatom :您无需添加依赖项即可阅读其代码并查看其完成方式(而不是期望这里的人们无缘无故地重新发明轮子)。
  • @ildjarn -- 我不敢苟同。考虑到限制,您所说的几乎对任何事情都是正确的。帮助从复杂的机器中提取轮子的精髓,似乎是一个值得提出的问题,并且与 StackOverflow 平台相关。
  • 好吧,一个懒惰的问题可以得到一个有用的答案,是的;但这并不是一个好问题(而且 IMO 说“我知道可以完全按照我的要求执行的代码,但我拒绝阅读它”构成懒惰)。 ;-]

标签: c++ tuples c++14 metaprogramming


【解决方案1】:

这个问题分几个部分解决。

在第一部分,让我们创建一个template<typename type_2_search, typename ...all_types> class type_search; 来确定@​​987654323@ 是否是...all_types 中的任何类型

#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;
}

结果输出是:

0
1
1
1

下一部分是template&lt;typename type, bool value, typename tuple_bag&gt; class add_2_bag_if_type_in_tuple;。第一个参数是类型。第三个参数是std::tuple&lt;types...&gt;。如果第二个booltrue,模板会返回一个std::tuple&lt;type, types...&gt;,它会添加元组的类型。否则,它会返回相同的元组。相当简单:

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;
};

我们现在有所有缺失的部分来创建tuple_intersection 模板,在最后一部分。我们遍历第一个元组的类型,使用第一个模板检查每个类型与第二个元组中的类型,然后将结果传递给第二个模板。

首先,特化,当我们到达第一个元组类型的末尾时:

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;
};

对于拼图的最后一块:从第一个元组中取出第一个类型,递归使用 compute_intersection 计算第一个元组的其余部分与第二个元组的交集,然后 type_search 被拔出的-off 类型,然后 `add_2_bag_if_type_in_tuple:

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();
}

【讨论】:

  • 非常感谢 Sam 的详细解答。我不愿意不将此标记为已接受(我很愿意),但我非常喜欢 ms 的简洁回答。道歉。顺便说一句,由于其非递归性质,我更喜欢关于类型包含的第二个答案here。 PS - 我也没有足够的代表来投票 - 啊
  • @indivisibleatom :你现在就做。 ;-D
【解决方案2】:

您可以将indices trickhas_type 一起使用(来自here):

#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, "");
}

live example

【讨论】:

    猜你喜欢
    • 2010-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-27
    • 2012-09-19
    • 1970-01-01
    • 2012-01-07
    • 2019-11-07
    相关资源
    最近更新 更多