C++11: I can go from multiple args to tuple, but can I go from tuple to multiple args?
Try something like this:
// implementation details, users never invoke these directly
namespace detail
{
template <typename F, typename Tuple, bool Done, int Total, int... N>
struct call_impl
{
static void call(F f, Tuple && t)
{
call_impl<F, Tuple, Total == 1 + sizeof...(N), Total, N..., sizeof...(N)>::call(f, std::forward<Tuple>(t));
}
};
template <typename F, typename Tuple, int Total, int... N>
struct call_impl<F, Tuple, true, Total, N...>
{
static void call(F f, Tuple && t)
{
f(std::get<N>(std::forward<Tuple>(t))...);
}
};
}
// user invokes this
template <typename F, typename Tuple>
void call(F f, Tuple && t)
{
typedef typename std::decay<Tuple>::type ttype;
detail::call_impl<F, Tuple, 0 == std::tuple_size<ttype>::value, std::tuple_size<ttype>::value>::call(f, std::forward<Tuple>(t));
}
Example:
#include <cstdio>
int main()
{
auto t = std::make_tuple("%d, %d, %d\n", 1,2,3);
call(std::printf, t);
}
With some extra magic and using std::result_of
, you can probably also make the entire thing return the correct return value.
Unpacking arguments from tuples
I think that @Xeo's comment summed it up well. From 14.5.3 of the C++11 standard:
A pack expansion consists of a pattern and an ellipsis, the
instantiation of which produces zero or more instantiations of the
pattern in a list.
In your case, by the time you finish with the recursive template instantiation and end up in the partial specialization, you have
f(std::get<N>(std::forward<Tuple>(t))...);
...where N
is parameter pack of four int
s (0
, 1
, 2
, and 3
). From the standardese above, the pattern here is
std::get<N>(std::forward<Tuple>(t))
The application of the ...
ellipsis to the above pattern causes it to be expanded into four instantiations in list form, i.e.
f(std::get<0>(t), std::get<1>(t), std::get<2>(t), std::get<3>(t));
How to extract tuple into a function parameters
As mentioned in the comments, std::apply
is suitable for your case.
pthread_create(
&td, nullptr,
[](void* p) {
auto param = static_cast<typename signature<decltype(f)>::argument_type*>(p);
std::apply([](auto& f, auto&&... args) {
f(std::forward<decltype(args)>(args)...);
}, *param);
return (void*)nullptr;
},
&tp);
Demo.
Pass multiple arguments in form of tuple
You can use the *
operator to unpack the argument list:
input_tuple = (1,2,3)
instance_1 = InputStuff(*input_tuple)
Passing a tuple to a variadic mixin class
http://cpptruths.blogspot.fr/2012/06/perfect-forwarding-of-parameter-groups.html
Davidbrcz's solution as specified in his blog above was sufficient to solve my conundrum. The solution is rather complex so I'll direct you to his page for it, but the basic idea is to on-the-fly create a numeric index tuple, à la std::maketuple(0, 1, 2, ...) where the tuple contains each of the indices of the various members of the tuple you need to enumerate. Then you just use:
M(std::forward<ArgM>(std::get<IdxM>(argm))...)
For M as either C or H in the example above and ArgM the arguments to M and IdxM the equally sized tuple of indices. Because the lists are the same length, the list gets rolled out into parameters in tandem and the tuple is unpacked.
The limitation is because you want the complicated step of building the index tuple to be hidden as an implementation detail, you need to use Constructor Delegation such that the public constructor takes the 2 tuples which then delegates to the private constructor which takes 2 value tuples and 2 index tuples. GCC 4.7.2 supports Delegated Constructors, but 4.6.3 doesn't.
To get around this, you need to make the 4-parameter constructor (2 tuples of values, 2 tuples of indices) public and then I wrote a macro to fill in the index tuple parameters:
#if __GNUC__ < 4 || __GNUC_MINOR__ <= 6
#define ZEROPARAM , detail::make_indices<>::type()
#define ONEPARAM , detail::make_indices<int>::type()
#define TWOPARAM , detail::make_indices<int, int>::type()
#define THREEPARAM , detail::make_indices<int, int, int>::type()
#define FOURPARAM , detail::make_indices<int, int, int, int>::type()
#define FIVEPARAM , detail::make_indices<int, int, int, int, int>::type()
#define SIXPARAM , detail::make_indices<int, int, int, int, int, int>::type()
#define SEVENPARAM , detail::make_indices<int, int, int, int, int, int, int>::type()
#define EIGHTPARAM , detail::make_indices<int, int, int, int, int, int, int, int>::type()
#define NINEPARAM , detail::make_indices<int, int, int, int, int, int, int, int, int>::type()
#define TENPARAM , detail::make_indices<int, int, int, int, int, int, int, int, int, int>::type()
#else // __GNUC__ < 4 || __GNUC_MINOR__ <= 6
#define ZEROPARAM
#define ONEPARAM
#define TWOPARAM
#define THREEPARAM
#define FOURPARAM
#define FIVEPARAM
#define SIXPARAM
#define SEVENPARAM
#define EIGHTPARAM
#define NINEPARAM
#define TENPARAM
#endif // __GNUC__ < 4 || __GNUC_MINOR__ <= 6
And then add the appropriate macro following the construction of the given Tester, at least while there are still folks on GCC 4.6.3 while I work to get everyone to at least 4.7.2 and preferable 4.8.1. :)
I wish I could give Davidbrcz credit for the solution but at least this may be helpful for folks facing a similar problem to apply his solution in their specific case. The main thing is copy his make_indices template class to do the actual work; the rest is a cake walk!
Expanding tuples into arguments
myfun(*some_tuple)
does exactly what you request. The *
operator simply unpacks the tuple (or any iterable) and passes them as the positional arguments to the function. Read more about unpacking arguments.
unpacking a tuple to call a matching function pointer
The C++17 solution is simply to use std::apply
:
auto f = [](int a, double b, std::string c) { std::cout<<a<<" "<<b<<" "<<c<< std::endl; };
auto params = std::make_tuple(1,2.0,"Hello");
std::apply(f, params);
Just felt that should be stated once in an answer in this thread (after it already appeared in one of the comments).
The basic C++14 solution is still missing in this thread. EDIT: No, it's actually there in the answer of Walter.
This function is given:
void f(int a, double b, void* c)
{
std::cout << a << ":" << b << ":" << c << std::endl;
}
Call it with the following snippet:
template<typename Function, typename Tuple, size_t ... I>
auto call(Function f, Tuple t, std::index_sequence<I ...>)
{
return f(std::get<I>(t) ...);
}
template<typename Function, typename Tuple>
auto call(Function f, Tuple t)
{
static constexpr auto size = std::tuple_size<Tuple>::value;
return call(f, t, std::make_index_sequence<size>{});
}
Example:
int main()
{
std::tuple<int, double, int*> t;
//or std::array<int, 3> t;
//or std::pair<int, double> t;
call(f, t);
}
DEMO
Storing variable arguments to be forwarded later
What am i doing wrong here ?
Well... first of all you need to unpack the tuple; by example, using an helper function, something as follows (std::index_sequence
and std::make_index_sequence
are available from C++14; you're compiling C++17 so you can use they)
template <std::size_t ... Is>
void exec_helper (std::index_sequence<Is...> const &)
{ T* item = new T{std::get<Is>(_args)...}; }
virtual void exec() override {
exec_helper(std::make_index_sequence<sizeof...(Ps)>{});
std::cout << "done " << _actionId << std::endl;
}
But there are other problems.
By example: you can use perfect forwarding only with template arguments of the functions/methods, so not in this constructor
CustomAction(int id, Ps&&... args) : _actionId(id),
_args(std::make_tuple(std::forward<Ps>(args)...)) {
}
because Ps...
are template arguments of the class, not of the constructor.
Should works something as
template <typename ... Us>
CustomAction (int id, Us && ... args) : _actionId{id},
_args{std::forward<Us>(args)...}
{ }
And I suppose that
aq.push<CustomAction<Item>>(actionId, param);
should be
// ........................VVV
aq.push<CustomAction<Item, int>>(actionId, param);
Related Topics
Why Can't I Add a Qgridlayout to a Qmainwindow
Gmon.Out Is Not Written After Compiling with Gcc -Pg -G
Cannot Get Makefile to Build Each Object from Its Corresponding Source
Sending an Email from a C/C++ Program in Linux
Problems Cross Compiling Qt 4.7 from Source for Arm
Intercepting/Rerouting Tcp Syn Packets to C++ Program in Linux
How to Find What Version of Libstdc++ Library Is Installed on Your Linux MAChine
Gcc Style Weak Linking in Visual Studio
Convert Windows Filetime to Second in Unix/Linux
When to Use Std::Forward to Forward Arguments
C++11: I Can Go from Multiple Args to Tuple, But How to Go from Tuple to Multiple Args
How to Implode a Vector of Strings into a String (The Elegant Way)
Error When Compiling Some Simple C++ Code
C++ Overload Static Function with Non-Static Function
What Is the Purpose of Allocating a Specific Amount of Memory for Arrays in C++