In what way can I express that each parameter in a parameter pack to a variadic template is itself a parameter pack?
Consider this code:
template <typename... TS>
void use_tuple(std::tuple<TS...> arg0);
template <typename... TS0, typename... TS1>
void use_tuple(std::tuple<TS0...> arg0, std::tuple<TS1...> arg1);
I want use_tuple to be able to take any number of tuples. Right now I have to write it like this:
template <typename... TS0, typename... REST>
void use_tuple(std::tuple<TS0...> arg0, REST... rest);
void use_tuple(); // Terminates the recursion.
But I want to write it like this:
// Each ELEMENT in PACK_OF_PACKS is a parameter pack.
template <(typename...)... PACK_OF_PACKS>
void use_tuple(std::tuple<PACK_OF_PACKS...>... args);
Is this even possible? If so, how? If not, what else can I do? My goal for this code is to get at the types contained in all the tuples.
My ultimate goal is something like this:
template <typename...> void foo();
use_tuple(std::tuple<int, float, char>{},
std::tuple<double, short, std::string>{},
std::tuple<std::function<void()>, std::vector<int>>{});
// Results in a call to
// foo<int, float, char, double, short, std::string,
// std::function<void()>, std::vector<int>>();
But I want to implement this in a small, constant number of indirections that does not depend on the number of tuples passed or the number of elements in each. So no recursion.
If not, what else can I do?
Why not just pass the tuples themselves as Tuples..., and then extract the types in the body of use_tuple?
template <typename...>
using example = int;
template <typename... Ts>
void foo(Ts...) { }
template <typename... Tuples>
void use_tuple(Tuples...)
{
foo(typename types<Tuples>::template apply<example>{}...);
}
You can extract the types with an helper types class:
template <typename Tuple>
struct types;
template <typename... Ts>
struct types<std::tuple<Ts...>>
{
template <template <typename...> class T>
using apply = T<Ts...>;
};
live example on wandbox
My goal for this code is to get at the types contained in all the tuples.
Not sure if you want all of them as an unique pack or not. PACK_OF_PACKS suggests it actually. In this case, you can just use std::tuple_cat.
Something along this line should work:
template<typename... T>
void do_use_tuple(std::tuple<T...>) {
// T are the types you are looking for
}
template <typename... T>
void use_tuple(T&&... tuple) {
return do_use_tuple(std::tuple_cat(std::forward<T>(tuple)...));
}
If you are not interested in forwarding also the values, just use decltype and you can easily get it.
See here for more details.
If you don't want all the parameters packed together and you want to explore them one tuple at a time, you can do something like this instead:
template<typename T>
struct tag { using type = T; };
template<typename... T, typename F>
void use_one(std::tuple<T...> &&, F f) {
F(tag<T>{}...);
}
template <typename... T>
void use_tuple(T&&... tuple) {
int arr = { 0,
(use_one(std::forward<T>(tuple), [](auto... tag) {
// tag::type contains the types of each
// parameter of a tuple, a tuple at a time
}), 0)...
};
(void)arr;
}
It's easy to adjust the lambda and the other function involved if you want also to access the values.
I guess you have something like the following (C++17) in mind. Let me stress that I do not recommend it. One should clearly prefer std::tuple_cat.
http://coliru.stacked-crooked.com/a/c64f2cb9a79af3e2
#include <array>
#include <iostream>
#include <tuple>
#include <utility>
////////////////////////////////////////////////////////////////////////////////
template<class... Ts>
void foo() {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
////////////////////////////////////////////////////////////////////////////////
namespace detail {
struct Index {
std::size_t outer{};// identify the tuple
std::size_t inner{};// identify the element in the tuple
};
template<std::size_t... ns, class... Tuples>
constexpr void use_tuple(std::index_sequence<ns...>, Tuples...) {
constexpr auto inds = [&] () {
std::array<Index, sizeof...(ns)> inds{};
std::size_t n = 0;
for(std::size_t outer=0; outer<sizeof...(Tuples); ++outer) {
std::size_t size = std::begin({std::tuple_size<Tuples>::value...})[outer];
for(std::size_t inner=0; inner<size; ++inner) inds[n++] = {outer, inner};
}
return inds;
}();
using TupleTuple = std::tuple<Tuples...>;
foo<
std::tuple_element_t<
inds[ns].inner,
std::tuple_element_t<inds[ns].outer, TupleTuple>
>...
>();
}
}// detail
template<class... Tuples>
constexpr void use_tuple(Tuples... tuples) {
constexpr std::size_t N = (std::tuple_size<Tuples>{} + ...);
detail::use_tuple(std::make_index_sequence<N>{}, std::move(tuples)...);
}
////////////////////////////////////////////////////////////////////////////////
int main() {
std::tuple<int, unsigned, int> t0;
std::tuple<double, float> t1;
std::tuple<char, bool, bool, int> t2;
use_tuple(t0, t1, t2);
return 0;
}
Related
As the title says, I'm looking for the best way to enumerate the types on a tuple.
So my first attempt was the code below, which is an adaption of another answer here on stackoverflow, with the only change being that is wrapped on another class, so this doesn't require to pass the tuple type as template parameter:
#include <tuple>
using namespace std;
using uInt = size_t;
template<typename... ARGS>
class ECS_Data
{
private:
tuple<ARGS...> data;
private:
//TYPE INDEXING
template<typename T, typename Types>
struct Internal_Type_Index;
template<typename T>
struct Type_Index {
static constexpr uInt value = Internal_Type_Index<T, tuple<ARGS...>>::value;
};
template<typename T, typename U, typename... Types>
struct Internal_Type_Index<T, tuple<U, Types...>> {
static constexpr uInt value = 1 + Internal_Type_Index<T, tuple<Types...>>::value;
};
template<typename T, typename... Types>
struct Internal_Type_Index<T, tuple<T, Types...>> {
static constexpr uInt value = 0;
};
public:
template<typename T>
static constexpr uInt Type_Index_v = Type_Index<T>::value;
};
int main()
{
ECS_Data<int,float,double,long long,char> ecs_data;
return ecs_data.Type_Index_v<char>; //return 4
}
The "problem" with this is that for a tuple with 50 types let's say, it instantiate 1350 structs and each come with a static variable.
For example, for tuple<int,float,double>:
called with int would instantiate 1 struct Internal_Type_Index<int, tuple<int, Types...>> and stop because int is immediately found.
Called with float would instantiate 2 structs Internal_Type_Index<float, tuple<int, Types...>> and then Internal_Type_Index<float, tuple<float, Types...>> then stop because float is found, and so on...resulting in 3+2+1 instantiations (assuming was Type_Index_v was called for all types).
So N + (N+N^2)/2 instantiation, right? N Type_Index and (N+N^2)/2 Internal_Type_Index partial specializations (all 1350 with a static variable inside of them).
My second solution is this:
#include <tuple>
#include <utility>
using namespace std;
using uInt = size_t;
template<typename... ARGS>
class ECS_Data
{
private:
tuple<ARGS...> data;
template<typename T>
inline static uInt _index = 0;
public:
ECS_Data() {
init_index(std::make_index_sequence<sizeof...(ARGS)>());
}
template<typename T>
uInt index()const { return _index<T>; }
private:
template<size_t... N>
void init_index(std::index_sequence<N...>) { (..., (_index<ARGS> = N)); }
};
int main()
{
ECS_Data<int,float,double,char> ecs_data;
return ecs_data.index<char>();
}
Still with the example of a tuple of 50 types, this time we have:
2+N instantiations from make_index_sequence
50 static templated variables from _index
50 member function instantiations from index<T>()
This seems better number wise, but it is runtime now, because I don't see a way to make _index constexpr while initializing it with a fold expression like in the code above.
So my questions would be:
1)Do you see a way to improve the code above?
2)Considering all (for example compiler optimization magic), at the end of the day which version is better?
3)There is a yet better version you can suggest?
EDIT:Forgive if is hard to read, the text editor here on stackoverflow completely ignored my newlines.
I would do:
template <typename T, typename Tuple, std::size_t ... Is>
constexpr std::size_t tuple_index_impl(std::index_sequence<Is...>)
{
// You might adapt here to handle duplicate differently
return std::max({ std::is_same<T, std::tuple_element_t<Is, Tuple>>::value * (Is + 1)... });
}
template <typename T, typename Tuple>
constexpr std::size_t tuple_index()
{
return tuple_index_impl<T, Tuple>(std::make_index_sequence<std::tuple_size<Tuple>::value>());
}
Demo
One instantiation of both methods by type + std::index_sequence (which might be done magically by compiler in 1 unique instantiation).
I'll only take a shot at 3). My shot would look something like this:
template <typename Tuple, typename Needle, std::size_t... I>
constexpr std::size_t tuple_index_impl(std::index_sequence<I...>) {
// don't use std::disjunction_v here as it will return bool
constexpr std::size_t idx = std::disjunction<
// need I+1 to prevent a falsy result on index 0
std::integral_constant<std::size_t,
(I+1) * std::is_same_v<std::tuple_element_t<I, Tuple>, Needle>>...,
// fallthrough case
std::integral_constant<std::size_t, 0>
>::value;
static_assert(idx != 0, "type not found in tuple");
return idx - 1;
}
template <typename Tuple, typename Needle>
constexpr std::size_t tuple_index() {
return tuple_index_impl<Tuple, Needle>(
std::make_index_sequence<std::tuple_size_v<Tuple>>{});
}
Which could be used like
using T = std::tuple<int, long long, double, char, double>;
//std::cout << tuple_index<T, float>(); //ERROR: type not found in tuple
std::cout << tuple_index<T, double>(); // prints "2", the first one
std::cout << tuple_index<T, char>(); // prints "3"
Live: http://coliru.stacked-crooked.com/a/8ea39202298f2ddc
The key here is std::disjunction, which doesn't need to instantiate any template arguments after the value it has found. This will also work on any tuple-like type (things that implement the tuple_element and tuple_size interface).
Since this is obviously all constexpr/template magic, the only costs paid will be at compile time. How well this performs in that regard will depend on the efficiency of the compiler's std::tuple_element implementation, I would guess, but I haven't done any profiling.
In some contexts, it could be useful/necessary to have a for loop evaluated/unrolled at compile time. For example, to iterate over the elements of a tuple, one needs to use std::get<I>, which depends on a template int parameter I, hence it has to be evaluated at compile time.
Using compile recursion one can solve a specific problem, as for instance discussed here, here, and, specifically for std::tuple here.
I am interested, however, on how to implement a generic compile-time for loop.
The following c++17 code implements this idea
#include <utility>
#include <tuple>
#include <string>
#include <iostream>
template <int start, int end, template <int> class OperatorType, typename... Args>
void compile_time_for(Args... args)
{
if constexpr (start < end)
{
OperatorType<start>()(std::forward<Args>(args)...);
compile_time_for<start + 1, end, OperatorType>(std::forward<Args>(args)...);
}
}
template <int I>
struct print_tuple_i {
template <typename... U>
void operator()(const std::tuple<U...>& x) { std::cout << std::get<I>(x) << " "; }
};
int main()
{
std::tuple<int, int, std::string> x{1, 2, "hello"};
compile_time_for<0, 3, print_tuple_i>(x);
return 0;
}
While the code works, it would be nicer to be able to simply provide a template function to the routine compile_time_for, rather than a template class to be instantiated at each iteration.
A code like the following, however, does not compile in c++17
#include <utility>
#include <tuple>
#include <string>
#include <iostream>
template <int start, int end, template <int, typename...> class F, typename... Args>
void compile_time_for(F f, Args... args)
{
if constexpr (start < end)
{
f<start>(std::forward<Args>(args)...);
compile_time_for<start + 1, end>(f, std::forward<Args>(args)...);
}
}
template <int I, typename... U>
void myprint(const std::tuple<U...>& x) { std::cout << std::get<I>(x) << " "; }
int main()
{
std::tuple<int, int, std::string> x{1, 2, "hello"};
compile_time_for<0, 3>(myprint, x);
return 0;
}
With gcc 7.3.0 and option std=c++17 the first error is
for2.cpp:7:25: error: ‘auto’ parameter not permitted in this context
void compile_time_for(F f, Args... args)
The questions are:
Is there a way to write compile_time_for such that it accepts a template function as its first argument?
If question 1. is positive, is there an overhead in the first working code, due to the fact that the routine create an object of type OperatorType<start> at every loop iteration?
Are there plans to introduce a feature like a compile-time for loop in the upcoming c++20?
Is there a way to write compile_time_for such that it accepts a template function as its first argument?
Short answer: no.
Long answer: a template function isn't an object, is a collection of objects and you can pass to a function, as an argument, an object, non a collection of objects.
The usual solution to this type of problem is wrap the template function inside a class and pass an object of the class (or simply the type, if the function is wrapped as a static method). That is exactly the solution you have adopted in your working code.
If question 1. is positive, is there an overhead in the first working code, due to the fact that the routine create an object of type OperatorType at every loop iteration?
Question 1 is negative.
Are there plans to introduce a feature like a compile-time for loop in the upcoming c++20?
I don't know C++20 enough to respond this question but I suppose not passing a set of function.
Anyway, you can do a sort of compile-time for loop using std::make_index_sequence/std::index_sequence starting from C++14.
By example, if you accept to extract the touple value outside your myprint() function, you can wrap it inside a lambda and write something as follows (using also C++17 template folding; in C++14 is a little more complicated)
#include <utility>
#include <tuple>
#include <string>
#include <iostream>
template <typename T>
void myprint (T const & t)
{ std::cout << t << " "; }
template <std::size_t start, std::size_t ... Is, typename F, typename ... Ts>
void ctf_helper (std::index_sequence<Is...>, F f, std::tuple<Ts...> const & t)
{ (f(std::get<start + Is>(t)), ...); }
template <std::size_t start, std::size_t end, typename F, typename ... Ts>
void compile_time_for (F f, std::tuple<Ts...> const & t)
{ ctf_helper<start>(std::make_index_sequence<end-start>{}, f, t); }
int main()
{
std::tuple<int, int, std::string> x{1, 2, "hello"};
compile_time_for<0, 3>([](auto const & v){ myprint(v); }, x);
return 0;
}
If you really want extract the tuple element (or tuples elements) inside the function, the best I can imagine is transform your first example as follows
#include <utility>
#include <tuple>
#include <string>
#include <iostream>
template <std::size_t start, template <std::size_t> class OT,
std::size_t ... Is, typename... Args>
void ctf_helper (std::index_sequence<Is...> const &, Args && ... args)
{ (OT<start+Is>{}(std::forward<Args>(args)...), ...); }
template <std::size_t start, std::size_t end,
template <std::size_t> class OT, typename... Args>
void compile_time_for (Args && ... args)
{ ctf_helper<start, OT>(std::make_index_sequence<end-start>{},
std::forward<Args>(args)...); }
template <std::size_t I>
struct print_tuple_i
{
template <typename ... U>
void operator() (std::tuple<U...> const & x)
{ std::cout << std::get<I>(x) << " "; }
};
int main()
{
std::tuple<int, int, std::string> x{1, 2, "hello"};
compile_time_for<0u, 3u, print_tuple_i>(x);
return 0;
}
-- EDIT --
The OP asks
Is there some advantage of using index_sequence over my first code?
I'm not an expert but this way you avoid recursion.
Compilers have recursion limits, from the template point of view, that can be strict. This way you avoid they.
Also, your code does not compile if you set the template parameters end > start. (One can imagine a situation where you want the compiler to determine if a loop is instantiated at all)
I suppose you mean that my code does not compile if start > end.
The bad part is that there aren't check about this problem so the compiler try to compile my code also in this case; so encounter
std::make_index_sequence<end-start>{}
where end - start is a negative number but used by a template that expect an unsigned number. So end - start become a very great positive number and this can cause problems.
You can avoid this problem imposing a static_assert() inside compile_time_for()
template <std::size_t start, std::size_t end,
template <std::size_t> class OT, typename... Args>
void compile_time_for (Args && ... args)
{
static_assert( end >= start, "start is bigger than end");
ctf_helper<start, OT>(std::make_index_sequence<end-start>{},
std::forward<Args>(args)...);
}
Or maybe you can use SFINAE to disable the function
template <std::size_t start, std::size_t end,
template <std::size_t> class OT, typename... Args>
std::enable_if_t<(start <= end)> compile_time_for (Args && ... args)
{ ctf_helper<start, OT>(std::make_index_sequence<end-start>{},
std::forward<Args>(args)...); }
If you want, using SFINAE you can add an overloaded compile_time_for() version to manage the end < start case
template <std::size_t start, std::size_t end,
template <std::size_t> class OT, typename ... Args>
std::enable_if_t<(start > end)> compile_time_for (Args && ...)
{ /* manage the end < start case in some way */ }
I'll answer on the question how to fix your last code sample.
The reason why it doesn't compile is here:
template <int start, int end, template <int, typename...> class F, typename... Args>
void compile_time_for(F f, Args... args)
/\
F is a template, you can't have an object of a template class without template parameters being substituted. E.g. you can't have on object of std::vector type, but can have object of std::vector<int>. I suggest you to make F functor with a template operator() :
#include <utility>
#include <tuple>
#include <string>
#include <iostream>
template <int start, int end, typename F, typename... Args>
void compile_time_for(F f, Args... args)
{
if constexpr (start < end)
{
f.template operator()<start>(std::forward<Args>(args)...);
compile_time_for<start + 1, end>(f, std::forward<Args>(args)...);
}
}
struct myprint
{
template <int I, typename... U>
void operator()(const std::tuple<U...>& x) { std::cout << std::get<I>(x) << " "; }
};
int main()
{
std::tuple<int, int, std::string> x{1, 2, "hello"};
compile_time_for<0, 3>(myprint(), x);
return 0;
}
This question already has answers here:
"unpacking" a tuple to call a matching function pointer
(9 answers)
Closed 5 years ago.
In C++14, you can do something like this:
struct Placeholder
{
template<typename T>
constexpr static T fct(T val) { return val; }
};
int main()
{
constexpr int i{};
auto fct = [](auto&& placeholder) -> decltype(placeholder.fct(i)) { return 5.5f; };
static_assert(fct(Placeholder{}) == 5, "");
}
For the sake of the example, consider that Placeholder::fct is actually manipulating the input type to something else (in the present case the function call is useless).
On the other hand, in C++11, you can simulate generic lambdas by declaring a templated functor. In fact, I could simply pass i to the constructor and store it as a member, like so:
template<typename T>
class Functor
{
T i;
public:
constexpr Functor(T i) : i{ i } {}
template<typename P>
constexpr auto operator()(P&& placeholder) const -> decltype(placeholder.fct(i))
{
return 5.5f;
}
};
int main()
{
constexpr int i{};
constexpr Functor<decltype(i)> fct(i);
static_assert(fct(Placeholder{}) == 5, "");
}
The problem comes when we want the Placeholder to take a variadic number of arguments, like so:
struct Placeholder
{
template<typename... T>
constexpr static auto fct(T... val) -> typename std::common_type<T...>::type
{
return { /* Do something with the values */ };
}
};
In fact, in C++14, we could simply pass the values directly to the lambda:
decltype(placeholder.fct(1, 2, 3))
However, in C++11, since we can't store a variadic number of members in a class, I don't see how I could achieve the exact same result. Any ideas?
From my understanding, a pure C++11 solution can be worked out from #RichardHodges 's idea. You need to recode std::apply by hand. To that end, you also need to recode std::integer_sequence, std::index_sequence and std::make_index_sequence. Let's start with that:
template <typename T, T... Is>
struct integral_sequence {};
template <std::size_t... Is>
using index_sequence = integral_sequence<std::size_t, Is...>;
template <typename Seq, typename T, T... el>
struct append_sequence;
template <typename T, T... el, T... Is>
struct append_sequence<integral_sequence<T, Is...>, T, el...> {
using type = integral_sequence<T, Is..., el...>;
};
namespace details {
template <std::size_t N>
struct make_index_sequence_impl {
private:
using seq = typename make_index_sequence_impl<N-1>::type;
public:
using type = typename append_sequence<seq, std::size_t, N>::type;
};
template <>
struct make_index_sequence_impl<0u> {
using type = index_sequence<0>;
};
template <std::size_t N>
struct make_index_sequence {
using type = typename make_index_sequence_impl<N-1>::type;
};
template <>
struct make_index_sequence<0u> {
using type = index_sequence<>;
};
} // namespace details
template <std::size_t N>
using make_index_sequence = typename details::make_index_sequence<N>::type;
Now, we can tackle the apply implementation. Its goal is to take a tuple as input and forward its content unpacked. For example, apply([](int x, int y) { /* impl */ }, std::make_tuple(0, 2)) is equivalent to [](int x, int y) { /* ... */ }(0, 2)
To do that we first need to dispatch a tuple content to a functor using an index_sequence:
namespace details {
template <typename F, typename Tuple, std::size_t... Is>
auto apply_impl(F&& ftor, Tuple&& tuple, index_sequence<Is...>) -> decltype(std::forward<F>(ftor)(std::get<Is>(tuple)...)) {
return std::forward<F>(ftor)(std::get<Is>(tuple)...);
}
} // namespace details
Then, the exposed apply comes in:
template <typename F, typename Tuple>
template <typename F, typename Tuple>
auto apply(F&& ftor, Tuple&& tuple) -> decltype(details::apply_impl(std::forward<F>(ftor), std::forward<Tuple>(tuple), make_index_sequence<std::tuple_size<typename std::remove_reference<Tuple>::type>::value>())){
return details::apply_impl(std::forward<F>(ftor), std::forward<Tuple>(tuple), make_index_sequence<std::tuple_size<typename std::remove_reference<Tuple>::type>::value>());
}
Now we can get the behavior you desired by storing a tuple inside your class and using apply to dispatch its content to your placeholder functor:
template <typename... Ts>
class Functor {
std::tuple<Ts...> is;
public:
constexpr Functor(Ts... ts) : is(std::make_tuple(ts...)) {}
template <typename P>
constexpr auto operator()(P&& placeholder) -> decltype(apply(std::forward<P>(placeholder), is)) {
return apply(std::forward<P>(placeholder), is);
}
};
Putting it all together with some examples leads to this Live Demo
Consider the following struct:
struct Test {
char a;
short b;
int c;
long long d;
void transformTest() {
// Pseudo
foreach datamember (regardless of type) of Test
call someTransform(datamember)
}
};
We could also pass a lambda, function pointer, functor, whatever into the transformTest(), that's not my concern as of right now.
What's the best way to do this?
The best way is to do it explicitly:
someTransform(a);
someTransform(b);
someTransform(c);
someTransform(d);
Of course, you'll need an appropriate number of overloads of someTransform().
If you really, really don't like that, there's always Boost Fusion. With that you can put your values together in a structure which the library understands and then can iterate over. This won't be worth doing for simple use cases.
Sounds like a case for Boost Fusion and its for_each() function combined with BOOST_FUSION_ADAPT_STRUCT. This stuff can work some miracles! Here's an example on how you can do it:
#include <boost/fusion/include/algorithm.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <iostream>
using namespace boost::fusion;
struct Print
{
template <typename T>
void operator()( T && t ) const
{
std::cout << t << ' ';
}
};
struct Test {
char a;
short b;
int c;
long long d;
void printTest() const;
};
BOOST_FUSION_ADAPT_STRUCT(
Test,
(char, a)
(short, b)
(int, c)
(long long, d)
)
void Test::printTest() const
{
for_each ( *this, Print() );
}
int main()
{
const auto t = Test();
t.printTest();
}
Step 1: Wrap your data in a tuple. Possibly a temporary one.
Step 2: Wrap your callable in a functor.
Step 3: Write a tuple_foreach that applies a functor to each element of a tuple.
For step 1, I'd advise leaving the data where it is, and just using a std::tie to create a tuple of references.
For step 2, a simple perfect forwarding functor looks like:
#define RETURNS(X) ->decltype(X) { return (X); }
struct foo_functor {
template<typename... Args>
auto operator()(Args&&... args) const
RETURNS( foo( std::forward<Args>(args)... ) )
};
which represents the override set of functions called foo, and wraps that into a single object which automatically dispatches any call to the appropriate overload of foo.
For step 3, it isn't hard. Just use the indexes trick to run code on each element of a tuple:
void do_in_order() {}
template<typename Lambda, typename... Lambdas>
void do_in_order( Lambda&& closure, Lambdas&&... closures ) {
std::forward<Lambda>(closure)();
do_in_order( std::forward<Lambdas>(closures)... );
}
template<unsigned... Is>
struct seq { typedef seq<Is> type; }
template<unsigned Max, unsigned... Is>
struct make_seq:make_seq<Max-1, Max-1, Is...> {};
template<unsigned... Is>
struct make_seq<0,Is...>:seq<Is...> {};
template<typename Tuple, typename Functor, unsigned... Is>
void foreach_tuple_helper( seq<Is...>, Tuple&& t, Functor&& f ) {
do_in_order(
[&]{ std::forward<Functor>(f)(std::get<Is>(std::forward<Tuple>(t))); }...
);
}
template<typename Tuple, typename Functor>
void foreach_tuple( Tuple&& t, Functor&& f ) {
foreach_tuple_helper( make_seq<std::tuple_size< typename std::decay<Tuple>::type >::value>(), std::forward<Tuple>(t), std::forward<Functor>(f) );
}
do_in_order doesn't work in clang last I checked, but an equivalent indexes trick that works on your compiler shouldn't be hard to google.
While Boost.Fusion is a good solution, I thought I'd add that in C++11 you could use std::tuple like this:
template <unsigned ... indices>
struct sequence
{
typedef sequence type;
};
template <unsigned size, unsigned ... indices>
struct static_range : static_range<size-1,size-1,indices...> {};
template <unsigned ... indices>
struct static_range<0, indices...> : sequence<indices...> {};
template <class Function, class Tuple, unsigned ... indices>
auto transform_impl(const Tuple & t, Function f, sequence<indices...>) ->
std::tuple<decltype(f(std::get<indices>(t)))...>
{
return std::make_tuple(f(std::get<indices>(t))...);
}
template <class Function, class Tuple>
auto transform_tuple(const Tuple & t, Function f) ->
decltype(transform_impl(t, f, static_range<std::tuple_size<Tuple>::value>()))
{
return transform_impl(t, f, static_range<std::tuple_size<Tuple>::value>());
}
The sequence/static_range classes have been invaluable in my code in expanding classes (not just std::tuples) by indices so that I can std::get them.
Other than that, I think the code is fairly straightforward, it should be noted however that with this method the order in which f is invoked on each tuple element is undefined.
Usage would look like:
std::tuple<char, short, int, long long> t;
struct addone
{ template <class T> auto operator()(T t) -> decltype(t+1) {return t + 1;}};
auto t2 = transform_tuple(t, addone());
The resulting tuple will not have the same types as the input tuple due to integral promotion, each will have type typename std::common_type<T,int>::type.
Is it possible to store a parameter pack somehow for a later use?
template <typename... T>
class Action {
private:
std::function<void(T...)> f;
T... args; // <--- something like this
public:
Action(std::function<void(T...)> f, T... args) : f(f), args(args) {}
void act(){
f(args); // <--- such that this will be possible
}
}
Then later on:
void main(){
Action<int,int> add([](int x, int y){std::cout << (x+y);}, 3, 4);
//...
add.act();
}
To accomplish what you want done here, you'll have to store your template arguments in a tuple:
std::tuple<Ts...> args;
Furthermore, you'll have to change up your constructor a bit. In particular, initializing args with an std::make_tuple and also allowing universal references in your parameter list:
template <typename F, typename... Args>
Action(F&& func, Args&&... args)
: f(std::forward<F>(func)),
args(std::forward<Args>(args)...)
{}
Moreover, you would have to set up a sequence generator much like this:
namespace helper
{
template <int... Is>
struct index {};
template <int N, int... Is>
struct gen_seq : gen_seq<N - 1, N - 1, Is...> {};
template <int... Is>
struct gen_seq<0, Is...> : index<Is...> {};
}
And you can implement your method in terms of one taking such a generator:
template <typename... Args, int... Is>
void func(std::tuple<Args...>& tup, helper::index<Is...>)
{
f(std::get<Is>(tup)...);
}
template <typename... Args>
void func(std::tuple<Args...>& tup)
{
func(tup, helper::gen_seq<sizeof...(Args)>{});
}
void act()
{
func(args);
}
And that it! So now your class should look like this:
template <typename... Ts>
class Action
{
private:
std::function<void (Ts...)> f;
std::tuple<Ts...> args;
public:
template <typename F, typename... Args>
Action(F&& func, Args&&... args)
: f(std::forward<F>(func)),
args(std::forward<Args>(args)...)
{}
template <typename... Args, int... Is>
void func(std::tuple<Args...>& tup, helper::index<Is...>)
{
f(std::get<Is>(tup)...);
}
template <typename... Args>
void func(std::tuple<Args...>& tup)
{
func(tup, helper::gen_seq<sizeof...(Args)>{});
}
void act()
{
func(args);
}
};
Here is your full program on Coliru.
Update: Here is a helper method by which specification of the template arguments aren't necessary:
template <typename F, typename... Args>
Action<Args...> make_action(F&& f, Args&&... args)
{
return Action<Args...>(std::forward<F>(f), std::forward<Args>(args)...);
}
int main()
{
auto add = make_action([] (int a, int b) { std::cout << a + b; }, 2, 3);
add.act();
}
And again, here is another demo.
You can use std::bind(f,args...) for this. It will generate a movable and possibly copyable object that stores a copy of the function object and of each of the arguments for later use:
#include <iostream>
#include <utility>
#include <functional>
template <typename... T>
class Action {
public:
using bind_type = decltype(std::bind(std::declval<std::function<void(T...)>>(),std::declval<T>()...));
template <typename... ConstrT>
Action(std::function<void(T...)> f, ConstrT&&... args)
: bind_(f,std::forward<ConstrT>(args)...)
{ }
void act()
{ bind_(); }
private:
bind_type bind_;
};
int main()
{
Action<int,int> add([](int x, int y)
{ std::cout << (x+y) << std::endl; },
3, 4);
add.act();
return 0;
}
Notice that std::bind is a function and you need to store, as data member, the result of calling it. The data type of that result is not easy to predict (the Standard does not even specify it precisely), so I use a combination of decltype and std::declval to compute that data type at compile time. See the definition of Action::bind_type above.
Also notice how I used universal references in the templated constructor. This ensures that you can pass arguments that do not match the class template parameters T... exactly (e.g. you can use rvalue references to some of the T and you will get them forwarded as-is to the bind call.)
Final note: If you want to store arguments as references (so that the function you pass can modify, rather than merely use, them), you need to use std::ref to wrap them in reference objects. Merely passing a T & will create a copy of the value, not a reference.
Operational code on Coliru
This question was from C++11 days. But for those finding it in search results now, some updates:
A std::tuple member is still the straightforward way to store arguments generally. (A std::bind solution similar to #jogojapan's will also work if you just want to call a specific function, but not if you want to access the arguments in other ways, or pass the arguments to more than one function, etc.)
In C++14 and later, std::make_index_sequence<N> or std::index_sequence_for<Pack...> can replace the helper::gen_seq<N> tool seen in 0x499602D2's solution:
#include <utility>
template <typename... Ts>
class Action
{
// ...
template <typename... Args, std::size_t... Is>
void func(std::tuple<Args...>& tup, std::index_sequence<Is...>)
{
f(std::get<Is>(tup)...);
}
template <typename... Args>
void func(std::tuple<Args...>& tup)
{
func(tup, std::index_sequence_for<Args...>{});
}
// ...
};
In C++17 and later, std::apply can be used to take care of unpacking the tuple:
template <typename... Ts>
class Action
{
// ...
void act() {
std::apply(f, args);
}
};
Here's a full C++17 program showing the simplified implementation. I also updated make_action to avoid reference types in the tuple, which was always bad for rvalue arguments and fairly risky for lvalue arguments.
I think you have an XY problem. Why go to all the trouble to store the parameter pack when you could just use a lambda at the callsite? i.e.,
#include <functional>
#include <iostream>
typedef std::function<void()> Action;
void callback(int n, const char* s) {
std::cout << s << ": " << n << '\n';
}
int main() {
Action a{[]{callback(13, "foo");}};
a();
}