两个排版/元组中的常见类型
Common types in two TypeSets / Tuples
我有两个元组 - TypeSets建模为元组,因此保证在其参数包中最多包含每个类型一次,确切地说 - (比如A = std::tuple<T1, T2>
和B = std::tuple<T2, T3>
),我希望获得一个类型def,它对应于A
和B
交集中的类型元组(在这种情况下,tuple_intersect<A,B>::type = std::tuple<T2>
)。我该怎么做?
您可以将索引技巧与has_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, "");
}
现场示例
这个问题分几个部分解决。
在第一部分中,让我们创建一个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();
}
如果返回的一个类型不是默认可构造的,则来自 @m.s. 的答案不起作用。这是因为make_intersection
尝试在获取返回类型之前创建生成的元组。
我们可以通过仅处理类型来避免这种情况:
#include <tuple>
#include <type_traits>
// ##############################################
// from https://stackoverflow.com/a/25958302/678093
// (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, "");
}
- C++:TypeDef使用元组
- Pybind11:将元组列表从Python传递到C++
- 重载元组索引运算符-C++
- 在C++中,如何通过几种类型从元组中选择多个元素
- 将fold表达式与std::一起用于两个元组
- std::ranges::elements_view,用于自定义类似元组的数据
- 将元组的向量转换/构造为堆
- 专用于 std 元组的模板,而无需用户执行remove_cvref
- 将元组的向量构造成堆
- 元组由 Swig 生成的 Python 包装器返回,用于C++向量
- 将元组类型扩展为可变参数模板?
- 时间复杂度 当具有复合数据类型(如元组或对)时?
- 类内部和外部静态 constexpr 元组之间的差异
- 可变参数模板与使用元组在参数中添加不同的数据对
- 访问和打印元组中的数据,并使用 C++14 使用模板函数显示数据
- boost::包含提升单元的元组的哈希值
- 我正在寻找一种优雅的方式来从元组向量创建tuple_element向量
- 如何在可变参数模板函数中遍历可变参数元组?
- 如何使用 SML 随机生成八进制元组
- 两个排版/元组中的常见类型