是否可以交流参数包
Is it possible to interleave parameter packs?
有可能使用C 11/14/1z,具有带有两个参数包的模板构造,其中,它可以用两个包装的两个包装来实例化其他模板构造?即,如果第一个包是T1_1,T1_2,T1_3,而第二个包是T2_1,T2_2和T2_3,则交织包将为T1_1,T2_1,T1_2,T2_2,T2_2,T1_3,T1_3,T2_3,T2_3,T2_3?我的猜测是"否",因为省略号不应适用于两个参数包元素指定器。但是,也许某种元组建设或递归建筑技巧可以起作用?
编辑:假设包装具有相等的长度(sizeof...
值),让我明确说明。如果不会使事情变得更加令人费解,则可以解决各种长度的解决方案。
使用 tuple_cat
是过度的。更不用说不必要地约束了。
Trivial Pack类:
template<class...> struct pack {};
一个变色的concat,写得很小:
template<class T = pack<>, class...>
struct concat { using type = T; };
template<class... T1, class... T2, class... Ts>
struct concat<pack<T1...>, pack<T2...>, Ts...>
: concat<pack<T1..., T2...>, Ts...> {};
template<class... Ts>
using concat_t = typename concat<Ts...>::type;
然后,交织本身同样微不足道 - 扩展到两种类型的包装中,然后将它们加入:
template<class... Us>
struct interleave {
template<class... Vs>
using with = concat_t<pack<Us, Vs>...>;
};
演示。
实际上已经添加到标准中。我现在无法自己测试,但是这个想法应该起作用。
template <class Tuple1, class Tuple2, std::size_t ... indices>
auto interleave(Tuple1 t1, Tuple2 t2, std::integer_sequence<std::size_t, indices...>)
{
return std::tuple_cat(std::make_tuple(std::get<indices>(t1),
std::get<indices>(t2))...);
}
template <class Tuple1, class Tuple2>
auto interleave(Tuple1 t1, Tuple2 t2)
{
return interleave(t1, t2, std::make_index_sequence<std::tuple_size<Tuple1>::value>());
}
带有功能和 decltype
s,您可以轻松地做到这一点。
这是一个工作示例:
#include<tuple>
template<std::size_t... I>
constexpr auto f(std::index_sequence<I...>, auto tup1, auto tup2) {
return std::tuple_cat(std::make_tuple(std::get<I>(tup1), std::get<I>(tup2))...);
}
template<typename... V>
struct S {
template<typename... U, std::enable_if_t<(sizeof...(V) == sizeof...(U))>* = nullptr>
static auto generate() {
return f(std::make_index_sequence<sizeof...(U)>(), std::tuple<V...>{}, std::tuple<U...>{});
}
};
int main() {
static_assert(
std::is_same<
decltype(S<int, double>::template generate<char, void*>()),
std::tuple<int, char, double, void*>
>::value,
"!"
);
}
确保可能。您可以通过包装器获得两个不同的包装:
template < typename L0, typename L1 >
struct interleave;
template < typename ... Pack >
struct pack {};
template < typename ... P0, typename ... P1 >
struct interleave<pack<P0...>, pack<P1...>>
{
using type = ???;
};
#include <tuple>
#include <iostream>
#include <utility>
#include <typeinfo>
template<class T1, class T2>
struct interleave
{
static constexpr std::size_t size = std::tuple_size<T1>::value;
static_assert(size == std::tuple_size<T2>::value, "");
template<class T> struct impl;
template<std::size_t...Is>
struct impl<std::index_sequence<Is...>>
{
using type = std::tuple
<
std::tuple<std::tuple_element_t<Is, T1>,
std::tuple_element_t<Is, T2>>...
>;
};
template<class T> struct dedup;
template<class...Ts>
struct dedup<std::tuple<Ts...>>
{
using type = decltype(std::tuple_cat(std::declval<Ts>()...));
};
using dups = typename impl<decltype(std::make_index_sequence<size>())>::type;
using type = typename dedup<dups>::type;
};
int main()
{
using t = interleave<std::tuple<int, char, float>, std::tuple<unsigned, double, const char*>>::type;
std::cout << typeid(t).name() << std::endl;
}
aim:
获得类型的别名:
Foo<int, double, char, const char*>
使用2个参数包:
using Pack1 = Pack<int, char>;
using Pack2 = Pack<double, const char*>;
然后交织在一起:
typename ToFoo<Pack1, Pack2>::type
并执行它们等效的static_assert
:
using T1 = Foo<int, double, char, const char*>;
using T2 = typename ToFoo<Pack<int, char>, Pack<double, const char*>>::type;
static_assert(std::is_same<T1, T2>::value, "passed");
解决方案:
我们可以将2个元素交织成1个,如下所示:
template <class Tuple1, class Tuple2, std::size_t ... indices>
auto interleave(Tuple1 t1, Tuple2 t2, std::integer_sequence<std::size_t, indices...>)
{
return std::tuple_cat(std::make_tuple(std::get<indices>(t1),
std::get<indices>(t2))...);
}
template <class Tuple1, class Tuple2>
auto interleave(Tuple1 t1, Tuple2 t2)
{
return interleave(t1, t2, std::make_index_sequence<std::tuple_size<Tuple1>::value>());
}
我们可以按照以下方式获取所得交织的元组的类型:
template<typename... Ts>
struct Pack
{
using type = std::tuple<Ts...>;
};
template<typename T0, typename T1>
struct Interleaved;
template<typename... P0, typename... P1>
struct Interleaved<Pack<P0...>, Pack<P1...>>
{
using Pack0 = typename Pack<P0...>::type;
using Pack1 = typename Pack<P1...>::type;
using type = decltype(interleave(std::declval<Pack0>(), std::declval<Pack1>()));
};
然后,我们可以采用该std::tuple<Ts...>
类型,然后将其"转换"到Foo<Ts...>
,如下所示:
template<typename T>
struct TupleToFoo;
template<typename... Ts>
struct TupleToFoo<std::tuple<Ts...>>
{
using type = Foo<Ts...>;
};
最后,我们将其全部包装在一个辅助类ToFoo
上,该类别为2 Packs
并定义类型的别名:
template<typename T0, typename T1>
struct ToFoo;
template<typename... P0, typename... P1>
struct ToFoo<Pack<P0...>, Pack<P1...>>
{
using type = typename TupleToFoo<typename Interleaved<Pack<int, char>, Pack<double, const char*>>::type>::type;
};
完整的工作示例:(coliru)
#include <tuple>
template <class Tuple1, class Tuple2, std::size_t ... indices>
auto interleave(Tuple1 t1, Tuple2 t2, std::integer_sequence<std::size_t, indices...>)
{
return std::tuple_cat(std::make_tuple(std::get<indices>(t1),
std::get<indices>(t2))...);
}
template <class Tuple1, class Tuple2>
auto interleave(Tuple1 t1, Tuple2 t2)
{
return interleave(t1, t2, std::make_index_sequence<std::tuple_size<Tuple1>::value>());
}
template<typename... Ts>
struct Pack
{
using type = std::tuple<Ts...>;
};
template<typename T0, typename T1>
struct Interleaved;
template<typename... P0, typename... P1>
struct Interleaved<Pack<P0...>, Pack<P1...>>
{
using Pack0 = typename Pack<P0...>::type;
using Pack1 = typename Pack<P1...>::type;
using type = decltype(interleave(std::declval<Pack0>(), std::declval<Pack1>()));
};
template<typename... Ts>
struct Foo
{};
template<typename T>
struct TupleToFoo;
template<typename... Ts>
struct TupleToFoo<std::tuple<Ts...>>
{
using type = Foo<Ts...>;
};
template<typename T0, typename T1>
struct ToFoo;
template<typename... P0, typename... P1>
struct ToFoo<Pack<P0...>, Pack<P1...>>
{
using type = typename TupleToFoo<typename Interleaved<Pack<int, char>, Pack<double, const char*>>::type>::type;
};
int main()
{
using T1 = Foo<int, double, char, const char*>;
using T2 = typename ToFoo<Pack<int, char>, Pack<double, const char*>>::type;
static_assert(std::is_same<T1, T2>::value, "passed");
return 0;
}
- 在C++中,使用带有 std::optional 参数的函数<T>来表示可选参数是否有意义?
- 如何检查给定的参数是否为 cv::noArray()?
- 如果返回 -1,时间() 的参数是否被修改?
- C++中大多数/所有 setter 函数的参数是否应该写为常量引用?
- 检查两个模板参数是否相同
- 空函数的参数是否加载到缓存中?
- 使用 lambda 作为构造函数参数是否需要C++ 17?
- 了解'this'或其他参数是否为右值
- const-ref传递的模板化参数是否经过优化,以便在足够小时按值传递
- shared_ptr构造函数参数是否应按值传递
- 如何检查模板参数是否为给定值?
- 使用聚合初始化模拟默认函数参数是否存在任何陷阱?
- 在对象序列化期间添加额外参数是否有更好的方法?
- 通过 ssh 发送参数.是否有非阻塞输入函数?
- 如何检查运算符 != 模板参数是否存在 C++ 17?
- 常量引用函数参数:是否可以禁止临时对象?
- 如何检查模板参数是否为 std::variant?
- 是否可以确定函数的参数是否已签名或无符号,以实现可能性超载函数
- 移动 l 值参考参数是否是一种不好的做法?
- 显式指定通用 lambda 的 operator() 模板参数是否合法?