Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

C++0x: Tuple unpacking as arguments in function call

897 views
Skip to first unread message

metarox

unread,
Mar 12, 2009, 5:46:13 AM3/12/09
to
Hello,

I'd like to know what is the way to unpack a tuple into function call
arguments. I've seen in an old article for the standard that a
function called std::apply( Func, tuple ) did that, but it is nowhere
to be found in the gcc 4.3.2 C++0x implementation that I currently
experiment with.

void func( int a, int b, int c)
{

}


std::tuple <int, int, int> myargs(1, 2, 3);

would call something like this unwrapping the tuple into each of the
individual function arguments. I could write this wrapper myself, but
maybe it already exists in some form.

func( get<0>(myargs), get<1>(myargs), get<2>(myargs) );

I'm looking for the generic solution using variadic templates and
tuple manipulation if someone knows.

Thanks

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Anthony Williams

unread,
Mar 12, 2009, 10:16:55 AM3/12/09
to
metarox <legaul...@gmail.com> writes:

> I'd like to know what is the way to unpack a tuple into function call
> arguments. I've seen in an old article for the standard that a
> function called std::apply( Func, tuple ) did that, but it is nowhere
> to be found in the gcc 4.3.2 C++0x implementation that I currently
> experiment with.
>
> void func( int a, int b, int c)
> {
>
> }
>
>
> std::tuple <int, int, int> myargs(1, 2, 3);
>
> would call something like this unwrapping the tuple into each of the
> individual function arguments. I could write this wrapper myself, but
> maybe it already exists in some form.
>
> func( get<0>(myargs), get<1>(myargs), get<2>(myargs) );
>
> I'm looking for the generic solution using variadic templates and
> tuple manipulation if someone knows.

I am not aware of an easy technique other than to write your own apply
function, which isn't easy --- you have to recursively unpack the tuple
until you have unpacked all the elements into separate arguments, which
you can pass to your target function.

Anthony
--
Author of C++ Concurrency in Action | http://www.manning.com/williams
just::thread C++0x thread library | http://www.stdthread.co.uk
Just Software Solutions Ltd | http://www.justsoftwaresolutions.co.uk
15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK. Company No. 5478976

ymett

unread,
Mar 12, 2009, 2:39:26 PM3/12/09
to
On Mar 12, 11:46 am, metarox <legault.da...@gmail.com> wrote:
> Hello,
>
> I'd like to know what is the way to unpack a tuple into function call
> arguments.

Try the following:

template<bool enable, class T> struct enable_if {};
template<class T> struct enable_if<true, T> { typedef T type; };

template<size_t argIndex, size_t argSize, class... Args, class...
Unpacked, class F>
inline typename enable_if<(argIndex == argSize),
void>::type apply_args_impl(const std::tuple<Args...>&& t, F f,
Unpacked&&... u)
{
f(u...); // I think this should be f(std::forward<Unpacked>
(u)...);
}
template<size_t argIndex, size_t argSize, class... Args, class...
Unpacked, class F>
inline typename enable_if<(argIndex < argSize),
void>::type apply_args_impl(const std::tuple<Args...>&& t, F f,
Unpacked&&... u)
{
apply_args_impl<argIndex + 1, argSize>(t, f, u...,
std::get<argIndex>(t));
}

template<class... Args, class F>
inline void apply_args(const std::tuple<Args...>&& t, F f)
{
apply_args_impl<0, sizeof...(Args)>(t, f);
}


There are other possibilities, such as creating a list of indices.

Yechezkel Mett

Matti Rintala

unread,
Mar 12, 2009, 2:51:12 PM3/12/09
to
Anthony Williams wrote:
> metarox <legaul...@gmail.com> writes:
>> I'd like to know what is the way to unpack a tuple into function call
>> arguments. I've seen in an old article for the standard that a
>> function called std::apply( Func, tuple ) did that, but it is nowhere
>> to be found in the gcc 4.3.2 C++0x implementation that I currently
>> experiment with.
>>
>> I'm looking for the generic solution using variadic templates and
>> tuple manipulation if someone knows.
>
> I am not aware of an easy technique other than to write your own apply
> function, which isn't easy --- you have to recursively unpack the tuple
> until you have unpacked all the elements into separate arguments, which
> you can pass to your target function.

Here's one I managed to write using variadic templates in C++0x. This
compiles and works in gcc 4.3.2. It doesn't even require that function's
parameter types and tuple's types are exactly the same:

#include <tuple>

// Recursive case, unpack Nth argument
template<unsigned int N>
struct Apply_aux
{
template<typename... ArgsF, typename... ArgsT, typename... Args>
static void apply(void (*f)(ArgsF...), std::tuple<ArgsT...> const& t,
Args... args)
{
Apply_aux<N-1>::apply(f, t, std::get<N-1>(t), args...);
}
};

// Terminal case, call the function with unpacked arguments
template<>
struct Apply_aux<0>
{
template<typename... ArgsF, typename... ArgsT, typename... Args>
static void apply(void (*f)(ArgsF...), std::tuple<ArgsT...> const&,
Args... args)
{
f(args...);
}
};

// Actual apply function
template<typename... ArgsF, typename... ArgsT>
void apply(void (*f)(ArgsF...), std::tuple<ArgsT...> const& t)
{
Apply_aux<sizeof...(ArgsT)>::apply(f, t);
}

// Testing
#include <string>
#include <iostream>

void f(int p1, double p2, std::string p3)
{
std::cout << "int=" << p1 << ", double=" << p2 << ", string=" << p3
<< std::endl;
}

void g(int p1, std::string p2)
{
std::cout << "int=" << p1 << ", string=" << p2 << std::endl;
}

int main()
{
std::tuple<int, double, char const*> tup(1, 2.0, "xxx");
apply(&f, tup);
apply(&g, std::make_tuple(4, "yyy"));
}

> g++ -std=c++0x tupleunpack.cc
> ./a.out
int=1, double=2, string=xxx
int=4, string=yyy


--
------------- Matti Rintala ------------ bi...@cs.tut.fi ------------
Painting is the art of inclusion. Photography is an art of exclusion.

Boris Rasin

unread,
Mar 12, 2009, 3:29:46 PM3/12/09
to
On Mar 12, 11:46 am, metarox <legault.da...@gmail.com> wrote:

> I'd like to know what is the way to unpack a tuple into function call
> arguments. I've seen in an old article for the standard that a
> function called std::apply( Func, tuple ) did that, but it is nowhere
> to be found in the gcc 4.3.2 C++0x implementation that I currently
> experiment with.
>
> void func( int a, int b, int c)
> {
>
> }
>
> std::tuple <int, int, int> myargs(1, 2, 3);
>
> would call something like this unwrapping the tuple into each of the
> individual function arguments. I could write this wrapper myself, but
> maybe it already exists in some form.
>
> func( get<0>(myargs), get<1>(myargs), get<2>(myargs) );
>
> I'm looking for the generic solution using variadic templates and
> tuple manipulation if someone knows.

Here is the code posted previously in this group.
One has to marvel at unsurpassed clarity :-)

#include <cstddef>
#include <tuple>
#include <utility>

template<std::size_t...> struct index_tuple{};

template<std::size_t I, typename IndexTuple, typename... Types>
struct make_indices_impl;

template<std::size_t I, std::size_t... Indices, typename T,
typename... Types>
struct make_indices_impl<I, index_tuple<Indices...>, T, Types...>
{
typedef typename make_indices_impl<I + 1, index_tuple<Indices...,
I>, Types...>::type type;
};

template<std::size_t I, std::size_t... Indices>
struct make_indices_impl<I, index_tuple<Indices...> >
{
typedef index_tuple<Indices...> type;
};

template<typename... Types>
struct make_indices : make_indices_impl<0, index_tuple<>, Types...>
{};

template <class... Args>
void some_func(Args&&...){}

template <class... Args>
class store
{
public:
store(Args... args) : members(args...) {}
void forward()
{
typedef typename make_indices<Args...>::type Indices;
return forward0(Indices(), members);
}
private:
template <std::size_t... Indices>
static void forward0(index_tuple<Indices...>,
std::tuple<Args...>&&args)
{
some_func(std::forward<Args>(std::get<Indices>(args))...);
}
std::tuple<Args...> members;
};

int main()
{
store<int, bool, double>(42, true, 1.2).forward();

metarox

unread,
Mar 12, 2009, 5:00:26 PM3/12/09
to
Thanks to all of you

Hopefully they add it in the <utility> header or somewhere so we don't
have to ask too often!

0 new messages