While trying to reply to this question, I found my self in the need of creating a bunch of parameters for a variadic function on the fly where:
在尝试回答这个问题时,我发现自己需要为动态变量函数创建一堆参数,其中:
- the number of the parameters is not given
- 没有给出参数的数量
- the types are all the same, but unknown (even if they must be default constructible)
- 类型都是相同的,但未知(即使它们必须是默认的可构造的)
At runtime, the standard containers and a for loop can be used to do that.
Anyway, I'd like to generate a set of parameters at compile time, so as to be able to forward them to a variadic function.
Because of that, a std::tuple
seemed the obvious solution.
在运行时,标准容器和for循环可用于执行此操作。无论如何,我想在编译时生成一组参数,以便能够将它们转发到可变参数函数。因此,std :: tuple似乎是一个明显的解决方案。
Here arose the question: given a size N
and a default constructible type T
at compile time, how can I write a function to generate a tuple of the given size?
这里提出了一个问题:在编译时给定一个大小为N和一个默认的可构造类型T,如何编写一个函数来生成给定大小的元组?
I'm looking for something like this:
我正在寻找这样的东西:
auto tup = gen<MyType, N>();
On SO is a notable example of a recursive generator based structs but I was struggling with a function based solution and I've not been able to find it anywhere.
在SO上是基于递归生成器的结构的一个值得注意的例子,但我正在努力使用基于函数的解决方案而且我无法在任何地方找到它。
2 个解决方案
#1
3
A correctly written forwarding function (a la std::apply
) should work with std::array<T, N>
and anything else that implements the std::tuple_size
/std::get
interface. That said,
正确编写的转发函数(la std :: apply)应该与std :: array
template<size_t, class T>
using T_ = T;
template<class T, size_t... Is>
auto gen(std::index_sequence<Is...>) { return std::tuple<T_<Is, T>...>{}; }
template<class T, size_t N>
auto gen() { return gen<T>(std::make_index_sequence<N>{}); }
#2
0
Here is a possible implementation of such a function:
以下是这种功能的可能实现:
#include<utility>
#include<tuple>
template<typename T>
constexpr auto
params(std::index_sequence<0>) {
return std::tuple<T>{};
}
template<typename T, std::size_t I, std::size_t... O>
constexpr auto
params(std::index_sequence<I, O...>) {
auto tup = std::tuple<T>{ T{} };
auto seq = std::make_index_sequence<sizeof...(O)>{};
return std::tuple_cat(tup, params<T>(seq));
}
template<typename T, std::size_t N>
constexpr auto
gen(std::integral_constant<std::size_t, N>) {
return params<T>(std::make_index_sequence<N>{});
}
int main() {
auto tup = gen<int>(std::integral_constant<std::size_t, 3>{});
static_assert(std::tuple_size<decltype(tup)>::value == 3, "!");
}
For the sake of simplicity, I've used int
as a type.
With a small effort, user defined types can be used and the constraint of having them default constructible can be relaxed.
为简单起见,我使用int作为类型。只需很少的努力,就可以使用用户定义的类型,并且可以放宽使其具有默认构造的约束。
#1
3
A correctly written forwarding function (a la std::apply
) should work with std::array<T, N>
and anything else that implements the std::tuple_size
/std::get
interface. That said,
正确编写的转发函数(la std :: apply)应该与std :: array
template<size_t, class T>
using T_ = T;
template<class T, size_t... Is>
auto gen(std::index_sequence<Is...>) { return std::tuple<T_<Is, T>...>{}; }
template<class T, size_t N>
auto gen() { return gen<T>(std::make_index_sequence<N>{}); }
#2
0
Here is a possible implementation of such a function:
以下是这种功能的可能实现:
#include<utility>
#include<tuple>
template<typename T>
constexpr auto
params(std::index_sequence<0>) {
return std::tuple<T>{};
}
template<typename T, std::size_t I, std::size_t... O>
constexpr auto
params(std::index_sequence<I, O...>) {
auto tup = std::tuple<T>{ T{} };
auto seq = std::make_index_sequence<sizeof...(O)>{};
return std::tuple_cat(tup, params<T>(seq));
}
template<typename T, std::size_t N>
constexpr auto
gen(std::integral_constant<std::size_t, N>) {
return params<T>(std::make_index_sequence<N>{});
}
int main() {
auto tup = gen<int>(std::integral_constant<std::size_t, 3>{});
static_assert(std::tuple_size<decltype(tup)>::value == 3, "!");
}
For the sake of simplicity, I've used int
as a type.
With a small effort, user defined types can be used and the constraint of having them default constructible can be relaxed.
为简单起见,我使用int作为类型。只需很少的努力,就可以使用用户定义的类型,并且可以放宽使其具有默认构造的约束。