通过将两个参数包的元素线程化为类型对来解包两个参数包
Unpacking two parameter packs by threading their elements to pairs of types
假设 N
用户指定的类型,我想要一个 return 长度 N
的 std::tuple
的函数,其中每个元素都是通过函数构造的调用某些函数(如下面的 func
所示):
#include <tuple>
#include <utility>
template <typename T>
T func(int x)
{
return T();
}
template<typename... T, std::size_t... I>
std::tuple<T...> build_tuple()
{
// How do I write this in a generic way?
return std::make_tuple(
func<std::string>(0),
func<int>(1),
func<int>(2)
);
// This won't work, obviously
// return std::make_tuple(func<T...>(I...));
}
int main()
{
build_tuple<std::string, int, int>();
}
本质上,我的问题是如何解压缩参数以获得类似于 "type0, 0"、"type1, 1" 等的东西,而不是 "type0, type1, ..., 0, 1, ...",如果这有意义的话。
这感觉像是一个常见问题,那么有惯用的解决方案吗?
如果 size_t
个参数是 0, 1, ...
,您可以简单地使用额外的间接级别:
template<class Tuple, std::size_t... I>
Tuple build_tuple_impl(std::index_sequence<I...>)
{
return std::make_tuple(
func<std::tuple_element_t<I, Tuple>>(I)...);
}
template<typename... Ts>
auto build_tuple()
{
using Tuple = std::tuple<Ts...>;
return build_tuple_impl<Tuple>(std::make_index_sequence<sizeof...(Ts)>{});
}
// Usage:
auto t = build_tuple<std::string, int, int>();
更一般的情况:
template<class Tuple, std::size_t... Is, std::size_t... I>
Tuple build_tuple_impl(std::index_sequence<Is...>, std::index_sequence<I...>)
{
constexpr std::size_t is[] = {Is...};
return std::make_tuple(
func<std::tuple_element_t<I, Tuple>>(is[I])...);
}
template<typename... Ts, std::size_t... Is>
auto build_tuple(std::index_sequence<Is...> is)
{
static_assert(sizeof...(Ts) == sizeof...(Is));
using Tuple = std::tuple<Ts...>;
return build_tuple_impl<Tuple>(is, std::make_index_sequence<sizeof...(Ts)>{});
}
// Usage:
auto t = build_tuple<std::string, int, int>(std::index_sequence<3, 4, 5>{});
不是说你不会写build_tuple<std::string, int, int, 3, 4, 5>()
。其中一个序列应该被打包成一个类型。
假设 N
用户指定的类型,我想要一个 return 长度 N
的 std::tuple
的函数,其中每个元素都是通过函数构造的调用某些函数(如下面的 func
所示):
#include <tuple>
#include <utility>
template <typename T>
T func(int x)
{
return T();
}
template<typename... T, std::size_t... I>
std::tuple<T...> build_tuple()
{
// How do I write this in a generic way?
return std::make_tuple(
func<std::string>(0),
func<int>(1),
func<int>(2)
);
// This won't work, obviously
// return std::make_tuple(func<T...>(I...));
}
int main()
{
build_tuple<std::string, int, int>();
}
本质上,我的问题是如何解压缩参数以获得类似于 "type0, 0"、"type1, 1" 等的东西,而不是 "type0, type1, ..., 0, 1, ...",如果这有意义的话。
这感觉像是一个常见问题,那么有惯用的解决方案吗?
如果 size_t
个参数是 0, 1, ...
,您可以简单地使用额外的间接级别:
template<class Tuple, std::size_t... I>
Tuple build_tuple_impl(std::index_sequence<I...>)
{
return std::make_tuple(
func<std::tuple_element_t<I, Tuple>>(I)...);
}
template<typename... Ts>
auto build_tuple()
{
using Tuple = std::tuple<Ts...>;
return build_tuple_impl<Tuple>(std::make_index_sequence<sizeof...(Ts)>{});
}
// Usage:
auto t = build_tuple<std::string, int, int>();
更一般的情况:
template<class Tuple, std::size_t... Is, std::size_t... I>
Tuple build_tuple_impl(std::index_sequence<Is...>, std::index_sequence<I...>)
{
constexpr std::size_t is[] = {Is...};
return std::make_tuple(
func<std::tuple_element_t<I, Tuple>>(is[I])...);
}
template<typename... Ts, std::size_t... Is>
auto build_tuple(std::index_sequence<Is...> is)
{
static_assert(sizeof...(Ts) == sizeof...(Is));
using Tuple = std::tuple<Ts...>;
return build_tuple_impl<Tuple>(is, std::make_index_sequence<sizeof...(Ts)>{});
}
// Usage:
auto t = build_tuple<std::string, int, int>(std::index_sequence<3, 4, 5>{});
不是说你不会写build_tuple<std::string, int, int, 3, 4, 5>()
。其中一个序列应该被打包成一个类型。