Related
Is there a way to create index tuple with compile-time known size like
std::tuple<int, int, ...> tup = make_index_tuple(100); // -> tup == (0, 1, 2, ..., 99)
Maybe somehow using std::make_index_sequence?
There is a kind of similar question about uninitialized tuple type but with structures involved
EDIT
I am trying to test my hand-written string formatting function with a signature like this
template<class... Args>
std::string format(std::string_view fmt, const Args&... args)
so I implemented a test, that requires to pass a sequence of ints 0, 1, 2, 3, ..., 99 to args. If there is a way to create tuple like so, then I could use std::apply to pass required arguments. If there are other ways i'd be glad to hear them too :)
pass a sequence of ints 0, 1, 2, 3, ..., 99 to [function arguments]
You don't need tuples. Do this:
template <std::size_t ...I>
void foo(std::index_sequence<I...>)
{
format("foo", I...);
}
int main()
{
foo(std::make_index_sequence<42>());
}
If you insist on std::apply, it understands std::array out of the box. You just need to handle the first parameter separately, since it's not an int.
const int n = 32;
std::array<int, n> array;
for (int i = 0; i < n; i++)
array[i] = i;
std::apply([](auto ...params){format("foo", params...);}, array);
For educational purposes, here's the answer to the original question. This is how you make a tuple:
template <typename T, typename I>
struct n_tuple_helper {};
template <typename T, std::size_t ...I>
struct n_tuple_helper<T, std::index_sequence<I...>>
{
using type = std::tuple<std::enable_if_t<I || true, T>...>;
};
template <typename T, std::size_t N>
using n_tuple = typename n_tuple_helper<T, std::make_index_sequence<N>>::type;
Now, n_tuple<int, 3> expands to std::tuple<int, int, int>
Above have mentioned how you could accomplish your idea by creating std::array. In case you still want to see how you should create a tuple:
template<typename T, T ...I>
auto make_tuple_sequence_helper(std::integer_sequence<T, I...>)
{
return std::make_tuple(I...);
}
template<std::size_t I, typename T>
auto make_tuple_sequence()
{
return make_tuple_sequence_helper(std::make_integer_sequence<T, I>());
}
Then you call it in main:
auto int_tuple = make_tuple_sequence<5, int>();
// Equivalent to `std::make_tuple(0,1,2,3,4)`
auto long_tuple = make_tuple_sequence<5, long>();
// Equivalent to `std::make_tuple(0l,1l,2l,3l,4l)`
auto size_t_tuple = make_tuple_sequence<5, std::size_t>();
// Equivalent to `std::make_tuple(0z,1z,2z,3z,4z)`
Note that you could also remove the typename T, if you know you only want tuple<int...> :
template<int ...I>
auto make_tuple_sequence_helper(std::integer_sequence<int, I...>)
{
return std::make_tuple(I...);
}
template<std::size_t I,>
auto make_tuple_sequence()
{
return make_tuple_sequence_helper(std::make_integer_sequence<int, I>());
}
And in main would be:
auto int_tuple = make_tuple_sequence<5>();
While the accepted answer should work for you too, I think it can still be improved. Since your goal appears to be calling the format function with an array of arguments, we will try solving this issue directly.
// declaration of format
template <typename ...Args>
std::string format(std::string_view fmt, const Args &...args);
// variadic template which uses type deduction to obtain the indices as template parameters
template <typename T, std::size_t ...I>
std::string format_arr_impl(std::string_view fmt,
T arr[sizeof...(I)],
std::index_sequence<I...>)
{
return format(fmt, arr[I]...);
}
// wrapper function, so that we don't have to call `std::make_index_sequence` each time
// this accepts a builtin array, but we can also add an overload for std::array
template <typename T, std::size_t N>
std::string format_arr(std::string_view fmt, T (&arr)[N])
{
return format_arr_impl(fmt, arr, std::make_index_sequence<N>());
}
// we can now call format for an array very easily
int main()
{
int data[] {11, 22, 33};
format_arr("{} {} {}", data);
}
Or alternatively, if you really insist on creating a tuple, we can also do the following:
// make use of the same index_sequence trick to deduce the indices
template <typename T, std::size_t ...I>
auto tuple_from_arr_impl(T arr[sizeof...(I)], std::index_sequence<I...>)
{
return std::make_tuple(arr[I]...);
}
// once again, we could also use a std::array instead of a reference to a builtin array
template <typename T, std::size_t N>
auto tuple_from_arr(std::string_view fmt, T (&arr)[N])
{
return tuple_from_arr_impl(fmt, arr, std::make_index_sequence<N>());
}
With the latter approach, we obtain a tuple where each member is an element of the array. We could then use std::apply to print the members.
This question was kind of asked before, but I'm not sure a satisfactory response was really offered. For me, I'm not interested in landing in a std::vector of std::string, per se, but rather a std::tuple.
For instance, if I've got std::vector<A>, std::vector<B>, and std::vector<C>, then I expect perhaps std::vector<std::tuple<A, B, C>>. Or, even std::set<std::tuple<A, B, C>>, if that was more appropriate.
Now, I could encode nested for loops, however, I'd like to do this via functions, template functions if possible, then I suppose variadic would be necessary to accomplish the task.
There are no guarantees that A, B, or C have anything to do with each other, much less conversion to std::string, as were proposed in a couple of the responses.
I want to say there could be a variadic solution to that, but I'm not exactly sure how to compose the std::vector<T> or std::vector<T>::value_type definitions.
If you want to compute the Cartesian product of heterogeneous vectors, you may do something like:
template <std::size_t N>
bool increase(const std::array<std::size_t, N>& sizes, std::array<std::size_t, N>& it)
{
for (std::size_t i = 0; i != N; ++i) {
const std::size_t index = N - 1 - i;
++it[index];
if (it[index] >= sizes[index]) {
it[index] = 0;
} else {
return true;
}
}
return false;
}
template <typename F, std::size_t ... Is, std::size_t N, typename Tuple>
void apply_impl(F&& f,
std::index_sequence<Is...>,
const std::array<std::size_t, N>& it,
const Tuple& tuple)
{
f(std::get<Is>(tuple)[it[Is]]...);
}
template <typename F, typename ... Ts>
void iterate(F&& f, const std::vector<Ts>&... vs)
{
constexpr std::size_t N = sizeof...(Ts);
std::array<std::size_t, N> sizes{{vs.size()...}};
std::array<std::size_t, N> it{{(vs.size(), 0u)...}};
do {
apply_impl(f, std::index_sequence_for<Ts...>(), it, std::tie(vs...));
} while (increase(sizes, it));
}
Demo
Consider following piece of code:
static constexpr size_t Num {2};
struct S {
std::array<size_t, Num> get () { return {1, 2}; }
};
struct S1 : S {};
struct S2 : S {};
struct M {
template <typename T>
typename std::enable_if<std::is_same<T, S1>::value, S1>::type get () const {
return S1 {};
}
template <typename T>
typename std::enable_if<std::is_same<T, S2>::value, S2>::type get () const {
return S2 {};
}
};
I want to have a function which merges two or more std::arrays making one std::array.
So far I ended with something like this:
template <typename Mode, typename... Rs, size_t... Ns>
std::array<size_t, sizeof... (Rs)*Num> get_array (const Mode& mode, Sequence::Sequence<Ns...>) {
return {std::get<Ns> (mode.template get<Rs...> ().get ())...};
}
I want to have that the following code
M m;
auto x = get_array<M, S1, S2> (m, Sequence::Make<2> {});
produces std::array<size_t, 4> filled with {1, 2, 1, 2}.
Where Sequence::Sequence and Sequence::Make are described here.
I know that placing ... of Rs is incorrect in this context (If sizeof... (Rs) is 1 then it is fine, std::array<size_t, 2> with {1, 2} is returned) but I have no idea where to put it to make expansion which looks like this:
std::get<0> (mode.template get<Rs[0]> ().get ()),
std::get<1> (mode.template get<Rs[0]> ().get ()),
std::get<0> (mode.template get<Rs[1]> ().get ()),
std::get<1> (mode.template get<Rs[1]> ().get ());
Of course Rs[0] I mean first type from parameter pack.
Is it even possible?
Assuming that we're using Xeo's index sequence implementation, we can do something like this:
First create a function for concatenating two arrays. It receives the arrays, plus an index sequence for each one (detail::seq is the index_sequence type)
template<class T, size_t N, size_t M, size_t... I, size_t... J>
std::array<T, N + M> concat(const std::array<T, N>& arr1, const std::array<T, M>& arr2, detail::seq<I...>, detail::seq<J...>)
{
return {arr1[I]..., arr2[J]...};
}
Next, call this function from your get_array function, except we're going to double the seq that we received from the call in main:
template<class MODE, class... T, size_t... I>
auto get_array(MODE m, detail::seq<I...>) ->decltype(concat(m.template get<T>().get()..., detail::seq<I...>{}, detail::seq<I...>{})){
return concat(m.template get<T>().get()..., detail::seq<I...>{}, detail::seq<I...>{});
}
The call in main looks just like it did in your code:
M m;
auto x = get_array<M, S1, S2>(m, detail::gen_seq<2>{});
Where detail::gen_seq is the implementation of make_index_sequence that Xeo had.
Live Demo
Note that I replaced unsigned with size_t in Xeo's index sequence impl.
In C++14 we don't need to implement seq or gen_seq, and we also wouldn't need a trailing -> decltype() after our function.
In C++17 it would be even easier to generalize our concatenation for an arbitrary number of arrays, using fold expressions.
Yes, this can be done, with the standard index_sequence tricks:
template <class T, std::size_t N1, std::size_t N2, std::size_t ... Is, std::size_t ... Js>
std::array<T, N1 + N2> merge_impl(const std::array<T, N1>& a1,
const std::array<T, N2>& a2,
std::index_sequence<Is...>,
std::index_sequence<Js...>) {
return {a1[Is]..., a2[Js]...};
}
template <class T, std::size_t N1, std::size_t N2>
std::array<T, N1 + N2> merge(const std::array<T, N1>& a1, const std::array<T, N2>& a2) {
return merge_impl(a1, a2,
std::make_index_sequence<N1>{},
std::make_index_sequence<N2>{});
}
index_sequence is only in the 14 standard, but can be easily implemented in 11; there are many resources (including on SO) that describe how to do so (edit: it's basically equivalent to your Sequence stuff, may as well get used to the standard names for them). Live example: http://coliru.stacked-crooked.com/a/54dce4a695357359.
To start with, this is basically asking to concatenate an arbitrary number of arrays. Which is very similar to concatenate an arbitrary number of tuples, for which there is a standard library function, even in C++11: std::tuple_cat(). That gets us almost there:
template <class... Ts, class M>
auto get_array(M m) -> decltype(std::tuple_cat(m.template get<Ts>()...)) {
return std::tuple_cat(m.template get<Ts>()...);
}
Note that I flipped the template parameters, so this is just get_array<T1, T2>(m) instead of having to write get_array<M, T1, T2>(m).
Now the question is, how do we write array_cat? We'll just use tuple_cat and convert the resulting tuple to an array. Assume an implementation of index_sequence is available (which is something you'll want in your collection anyway):
template <class T, class... Ts, size_t... Is>
std::array<T, sizeof...(Ts)+1> to_array_impl(std::tuple<T, Ts...>&& tup,
std::index_sequence<Is...> ) {
return {{std::get<Is>(std::move(tup))...}};
}
template <class T, class... Ts>
std::array<T, sizeof...(Ts)+1> to_array(std::tuple<T, Ts...>&& tup) {
return to_array_impl(std::move(tup), std::index_sequence_for<T, Ts...>());
}
template <class... Tuples>
auto array_cat(Tuples&&... tuples) -> decltype(to_array(std::tuple_cat(std::forward<Tuples>(tuples)...))) {
return to_array(std::tuple_cat(std::forward<Tuples>(tuples)...));
}
And that gives you:
template <class... Ts, class M>
auto get_array(M m) -> decltype(array_cat(m.template get<Ts>()...)) {
return array_cat(m.template get<Ts>()...);
}
which handles arbitrarily many types.
So here's for an arbitrary number of same-type arrays. We are basically implementing a highly restrictive version of tuple_cat, made substantially easier because the number of elements in the arrays is the same. I make use of a couple C++14 and 17 library features that are all readily implementable in C++11.
template<class, size_t> struct div_sequence;
template<size_t...Is, size_t Divisor>
struct div_sequence<std::index_sequence<Is...>, Divisor>
{
using quot = std::index_sequence<Is / Divisor...>;
using rem = std::index_sequence<Is % Divisor...>;
};
template<class T, size_t...Ns, size_t...Is, class ToA>
std::array<T, sizeof...(Ns)> array_cat_impl(std::index_sequence<Ns...>,
std::index_sequence<Is...>,
ToA&& t)
{
// NB: get gives you perfect forwarding; [] doesn't.
return {std::get<Is>(std::get<Ns>(std::forward<ToA>(t)))... };
}
template<class Array, class... Arrays,
class VT = typename std::decay_t<Array>::value_type,
size_t S = std::tuple_size<std::decay_t<Array>>::value,
size_t N = S * (1 + sizeof...(Arrays))>
std::array<VT, N> array_cat(Array&& a1, Arrays&&... as)
{
static_assert(std::conjunction_v<std::is_same<std::decay_t<Array>,
std::decay_t<Arrays>>...
>, "Array type mismatch");
using ind_seq = typename div_sequence<std::make_index_sequence<N>, S>::rem;
using arr_seq = typename div_sequence<std::make_index_sequence<N>, S>::quot;
return array_cat_impl<VT>(arr_seq(), ind_seq(),
std::forward_as_tuple(std::forward<Array>(a1),
std::forward<Arrays>(as)...)
);
}
We can also reuse the tuple_cat machinery, as in #Barry's answer. To sidestep potential QoI issues, avoid depending on extensions and also extra moves, we don't want to tuple_cat std::arrays directly. Instead, we transform the array into a tuple of references first.
template<class TupleLike, size_t... Is>
auto as_tuple_ref(TupleLike&& t, std::index_sequence<Is...>)
-> decltype(std::forward_as_tuple(std::get<Is>(std::forward<TupleLike>(t))...))
{
return std::forward_as_tuple(std::get<Is>(std::forward<TupleLike>(t))...);
}
template<class TupleLike,
size_t S = std::tuple_size<std::decay_t<TupleLike>>::value >
auto as_tuple_ref(TupleLike&& t)
-> decltype(as_tuple_ref(std::forward<TupleLike>(t), std::make_index_sequence<S>()))
{
return as_tuple_ref(std::forward<TupleLike>(t), std::make_index_sequence<S>());
}
We can then transform the tuple_cat'd references back into an array:
template <class R1, class...Rs, size_t... Is>
std::array<std::decay_t<R1>, sizeof...(Is)>
to_array(std::tuple<R1, Rs...> t, std::index_sequence<Is...>)
{
return { std::get<Is>(std::move(t))... };
}
template <class R1, class...Rs>
std::array<std::decay_t<R1>, sizeof...(Rs) + 1> to_array(std::tuple<R1, Rs...> t)
{
static_assert(std::conjunction_v<std::is_same<std::decay_t<R1>, std::decay_t<Rs>>...>,
"Array element type mismatch");
return to_array(t, std::make_index_sequence<sizeof...(Rs) + 1>());
}
Finally, array_cat itself is just
template <class... Arrays>
auto array_cat(Arrays&&... arrays)
-> decltype(to_array(std::tuple_cat(as_tuple_ref(std::forward<Arrays>(arrays))...)))
{
return to_array(std::tuple_cat(as_tuple_ref(std::forward<Arrays>(arrays))...));
}
Any decent optimizer should have little difficulty optimizing the intermediate tuples of references away.
I'm trying to split a std::array<T, N> into a tuple of smaller arrays, like std::tuple<std::array<T, N1>, std::array<T, N2>, ...> where N1 + N2 + ... = N.
namespace detail {
// Summation of the given values
template <class T>
constexpr T sum(const T& x) { return x; }
template <class T, class ...Args>
constexpr auto sum(const T& x, Args&&... args)
{ return x + sum(std::forward<Args>(args)...); }
}
template <class T, std::size_t... Ns>
constexpr
std::tuple<std::array<T, Ns>...>
f(const std::array<T, detail::sum(Ns...)>& x)
{
// How do I implement this function?
}
int main()
{
constexpr std::array<Foo, 5> arr = { ... };
constexpr auto t = f<Foo, 2,3>(arr);
}
Actually I already implemented f but it's based on a loop which simply creates an empty array and copies the elements of the given array, but it doesn't work if T is not default_constructible.
I tried to utilize std::integer_sequence and std::make_index_sequence, but I think i'm totally lost with no clue.
Can anyone help me implement the function please?
Write
template<class T,size_t...Is,size_t N>
std::array<T,sizeof...(Is)>
extract(std::array<T,N>const&,std::index_sequence<Is...>){
return {{arr[Is]...}};
}
now we just need to turn {1,2,3} into {{0},{1,2},{3,4,5}} roughly, with everything being C++ index sequences (so syntax).
Map {3,4,0} to {0,1,2} -- a count of indexes to subarrays. Then map {3,4,0} x 1 to {3,4,5,6} and similar for the others. That gives us the indexes inside the subarrays, which we feed to extract and bob is your uncle.
template<size_t n, size_t...counts>
constexpr auto
foo( std::index_sequence<counts...> )
-> offset_seq<
sum_n<n>(counts...),
std::make_index_sequence<get_n<n,counts...> >
>{ return {}; }
with various helpers to be written is the {3,4,0} x 1 to {3,4,5,6} portion, for example.
So I have some type X:
typedef ... X;
and a template function f:
class <typename T>
void f(X& x_out, const T& arg_in);
and then a function g:
void g(const X* x_array, size_t x_array_size);
I need to write a variadic template function h that does this:
template<typename... Args>
void h(Args... args)
{
constexpr size_t nargs = sizeof...(args); // get number of args
X x_array[nargs]; // create X array of that size
for (int i = 0; i < nargs; i++) // foreach arg
f(x_array[i], args[i]); // call f (doesn't work)
g(x_array, nargs); // call g with x_array
}
The reason it doesn't work is because you can't subscript args like that at runtime.
What is the best technique to replace the middle part of h?
And the winner is Xeo:
template<class T> X fv(const T& t) { X x; f(x,t); return x; }
template<class... Args>
void h(Args... args)
{
X x_array[] = { fv(args)... };
g(x_array, sizeof...(Args));
}
(Actually in my specific case I can rewrite f to return x by value rather than as an out parameter, so I don't even need fv above)
You could refactor or wrap f to return a new X instead of having it passed, since this would play pack expansion into the hand and make the function really concise:
template<class T>
X fw(T const& t){ X x; f(x, t); return x; }
template<class... Args>
void h(Args... args){
X xs[] = { fw(args)... };
g(xs, sizeof...(Args));
}
Live example.
And if you could change g to just accept an std::initializer_list, it would get even more concise:
template<class... Args>
void h(Args... args){
g({f(args)...});
}
Live example. Or (maybe better), you could also provide just a wrapper g that forwards to the real g:
void g(X const*, unsigned){}
void g(std::initializer_list<X> const& xs){ g(xs.begin(), xs.size()); }
template<class... Args>
void h(Args... args){
g({f(args)...});
}
Live example.
Edit: Another option is using a temporary array:
template<class T>
using Alias = T;
template<class T>
T& as_lvalue(T&& v){ return v; }
template<class... Args>
void h(Args... args){
g(as_lvalue(Alias<X[]>{f(args)...}), sizeof...(Args));
}
Live example. Note that the as_lvalue function is dangerous, the array still only lives until the end of the full expression (in this case g), so be cautious when using it. The Alias is needed since just X[]{ ... } is not allowed due to the language grammar.
If all of that's not possible, you'll need recursion to access all elements of the args pack.
#include <tuple>
template<unsigned> struct uint_{}; // compile-time integer for "iteration"
template<unsigned N, class Tuple>
void h_helper(X (&)[N], Tuple const&, uint_<N>){}
template<unsigned N, class Tuple, unsigned I = 0>
void h_helper(X (&xs)[N], Tuple const& args, uint_<I> = {}){
f(xs[I], std::get<I>(args));
h_helper(xs, args, uint_<I+1>());
}
template<typename... Args>
void h(Args... args)
{
static constexpr unsigned nargs = sizeof...(Args);
X xs[nargs];
h_helper(xs, std::tie(args...));
g(xs, nargs);
}
Live example.
Edit: Inspired by ecatmur's comment, I employed the indices trick to make it work with just pack expansion and with f and g as-is, without altering them.
template<unsigned... Indices>
struct indices{
using next = indices<Indices..., sizeof...(Indices)>;
};
template<unsigned N>
struct build_indices{
using type = typename build_indices<N-1>::type::next;
};
template <>
struct build_indices<0>{
using type = indices<>;
};
template<unsigned N>
using IndicesFor = typename build_indices<N>::type;
template<unsigned N, unsigned... Is, class... Args>
void f_them_all(X (&xs)[N], indices<Is...>, Args... args){
int unused[] = {(f(xs[Is], args), 1)...};
(void)unused;
}
template<class... Args>
void h(Args... args){
static constexpr unsigned nargs = sizeof...(Args);
X xs[nargs];
f_them_all(xs, IndicesFor<nargs>(), args...);
g(xs, nargs);
}
Live example.
Nice template as answer for first part of question:
template <class F, class... Args>
void for_each_argument(F f, Args&&... args) {
[](...){}((f(std::forward<Args>(args)), 0)...);
}
It's obvious: you don't use iteration but recursion. When dealing with variadic templates something recursive always comes in. Even when binding the elements to a std::tuple<...> using tie() it is recursive: It just happens that the recursive business is done by the tuple. In your case, it seems you want something like this (there are probably a few typos but overall this should work):
template <int Index, int Size>
void h_aux(X (&)[Size]) {
}
template <int Index, int Size, typename Arg, typename... Args>
void h_aux(X (&xs)[Size], Arg arg, Args... args) {
f(xs[Index], arg);
h_aux<Index + 1, Size>(xs, args...);
}
template <typename... Args>
void h(Args... args)
{
X xs[sizeof...(args)];
h_aux<0, sizeof...(args)>(xs, args...);
g(xs, sizeof...(args));
}
I think you won't be able to use nargs to define the size of the array either: Nothing indicates to the compiler that it should be a constant expression.
It's fairly simple to do with parameter pack expansion, even if you can't rewrite f to return the output parameter by value:
struct pass { template<typename ...T> pass(T...) {} };
template<typename... Args>
void h(Args... args)
{
const size_t nargs = sizeof...(args); // get number of args
X x_array[nargs]; // create X array of that size
X *x = x_array;
int unused[]{(f(*x++, args), 1)...}; // call f
pass{unused};
g(x_array, nargs); // call g with x_array
}
It should be possible just to write
pass{(f(*x++, args), 1)...}; // call f
but it appears g++ (4.7.1 at least) has a bug where it fails to order the evaluation of brace-initializer-list parameters as class initialisers. Array initialisers are OK though; see Sequencing among a variadic expansion for more information and examples.
Live example.
As an alternative, here's the technique mentioned by Xeo using a generated index pack; unfortunately it does require an extra function call and parameter, but it is reasonably elegant (especially if you happen to have an index pack generator lying around):
template<int... I> struct index {
template<int n> using append = index<I..., n>; };
template<int N> struct make_index { typedef typename
make_index<N - 1>::type::template append<N - 1> type; };
template<> struct make_index<0> { typedef index<> type; };
template<int N> using indexer = typename make_index<N>::type;
template<typename... Args, int... i>
void h2(index<i...>, Args... args)
{
const size_t nargs = sizeof...(args); // get number of args
X x_array[nargs]; // create X array of that size
pass{(f(x_array[i], args), 1)...}; // call f
g(x_array, nargs); // call g with x_array
}
template<typename... Args>
void h(Args... args)
{
h2(indexer<sizeof...(args)>(), std::forward<Args>(args)...);
}
See C++11: I can go from multiple args to tuple, but can I go from tuple to multiple args? for more information.
Live example.
Xeo is onto the right idea- you want to build some kind of "variadic iterator" that hides a lot of this nastiness from the rest of the code.
I'd take the index stuff and hide it behind an iterator interface modeled after std::vector's, since a std::tuple is also a linear container for data. Then you can just re-use it all of your variadic functions and classes without having to have explicitly recursive code anywhere else.