两个 TypeSets / Tuples 中的常见类型
Common types in two TypeSets / Tuples
我有两个元组 -- TypeSets 被建模为元组,因此保证每个类型在它们的参数包中最多包含一次,确切地说 --(比如 A = std::tuple<T1, T2>
和 B = std::tuple<T2, T3>
) ,我希望获得一个 typedef,它对应于 A
和 B
的交集中的类型元组(在本例中为 tuple_intersect<A,B>::type = std::tuple<T2>
)。我该怎么做?
这个问题分几个部分解决。
在第一部分中,让我们创建一个 template<typename type_2_search, typename ...all_types> class type_search;
来确定 type_2_search
是否是 ...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<typename type, bool value, typename tuple_bag> class add_2_bag_if_type_in_tuple;
。第一个参数是类型。第三个参数是std::tuple<types...>
。如果第二个 bool
是 true
,模板返回一个 std::tuple<type, types...>
,它添加了元组的类型。否则,它会返回相同的元组。相当简单:
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
摘下的类型,然后是 `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();
}
您可以使用 along with has_type
(from here):
#include <tuple>
#include <type_traits>
// ##############################################
// from
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, "");
}
来自@m.s的回答。如果 returned 的一种类型不是默认可构造的,则不起作用。这是因为 make_intersection
在我们获得 return 类型之前尝试创建结果元组。
我们可以通过只处理类型来避免这种情况:
#include <tuple>
#include <type_traits>
// ##############################################
// from
// (c++17 version)
template <typename T, typename Tuple>
struct has_type;
template <typename T, typename... Us>
struct has_type<T, std::tuple<Us...>>
: std::disjunction<std::is_same<T, Us>...> {};
// ##############################################
template <typename... Ts>
using tuple_cat_t =
decltype(std::tuple_cat(std::declval<Ts>()...));
template <typename S1, typename S2> struct intersect {
template <typename>
struct build_intersection;
template <std::size_t... Indices>
struct build_intersection<std::index_sequence<Indices...>> {
using type = tuple_cat_t<
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 = typename build_intersection<
std::make_index_sequence<std::tuple_size<S1>::value>>::type;
};
struct T1{};
struct T2{
T2(int) {};
};
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, "");
}
我有两个元组 -- TypeSets 被建模为元组,因此保证每个类型在它们的参数包中最多包含一次,确切地说 --(比如 A = std::tuple<T1, T2>
和 B = std::tuple<T2, T3>
) ,我希望获得一个 typedef,它对应于 A
和 B
的交集中的类型元组(在本例中为 tuple_intersect<A,B>::type = std::tuple<T2>
)。我该怎么做?
这个问题分几个部分解决。
在第一部分中,让我们创建一个 template<typename type_2_search, typename ...all_types> class type_search;
来确定 type_2_search
是否是 ...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<typename type, bool value, typename tuple_bag> class add_2_bag_if_type_in_tuple;
。第一个参数是类型。第三个参数是std::tuple<types...>
。如果第二个 bool
是 true
,模板返回一个 std::tuple<type, types...>
,它添加了元组的类型。否则,它会返回相同的元组。相当简单:
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
摘下的类型,然后是 `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();
}
您可以使用 has_type
(from here):
#include <tuple>
#include <type_traits>
// ##############################################
// from
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, "");
}
来自@m.s的回答。如果 returned 的一种类型不是默认可构造的,则不起作用。这是因为 make_intersection
在我们获得 return 类型之前尝试创建结果元组。
我们可以通过只处理类型来避免这种情况:
#include <tuple>
#include <type_traits>
// ##############################################
// from
// (c++17 version)
template <typename T, typename Tuple>
struct has_type;
template <typename T, typename... Us>
struct has_type<T, std::tuple<Us...>>
: std::disjunction<std::is_same<T, Us>...> {};
// ##############################################
template <typename... Ts>
using tuple_cat_t =
decltype(std::tuple_cat(std::declval<Ts>()...));
template <typename S1, typename S2> struct intersect {
template <typename>
struct build_intersection;
template <std::size_t... Indices>
struct build_intersection<std::index_sequence<Indices...>> {
using type = tuple_cat_t<
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 = typename build_intersection<
std::make_index_sequence<std::tuple_size<S1>::value>>::type;
};
struct T1{};
struct T2{
T2(int) {};
};
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, "");
}