How to extract params from template function parameter pack? - c++

I am implementing a variadic template function because I want to make calls with up to 7 params. My calls go like this.
foo(1, 2, "msg", 4, 5.0);
or
foo(3, 4.1, "msg");
The first parameter identifies a protocol to use, and every parameter thereafter is what I would like to place in struct Msg.
struct Msg {
int proto;
string str;
int a;
int b;
double d;
};
The biggest problem I'm having is, I don't know how to get the remaining parameters after the first and store them. I'd like to use the first param to tell which struct members are to be populated. The part that confuses me is that each recursive call changes the function sig.
template<typename T>
T bar(T t) {
cout << __PRETTY_FUNCTION__ << endl;
return t;
}
template<typename T, typename... Args>
void foo(T value, Args... args)
{
cout << __PRETTY_FUNCTION__ << endl;
Msg msg;
msg.proto = value;
switch (value) {
case PROTO_A:
// when calling 'foo(1, 2, "msg", 4, 5.0)'
// 1 is proto and placed in struct Msg (msg.proto = value)
// but how to get the remaining params from args into struct Msg
foo(args...);
break;
case PROTO_B:
foo(args...);
break;
default:
break;
}
send_msg(msg);
}

You may use it without recursion:
Your specific fill method, with un-call fallback (using SFINAE and priority):
struct overload_priority_low {};
struct overload_priority_high : overload_priority_low {};
template<typename... Args>
auto Fill_ProtoA(Msg& msg, overload_priority_high, Args... args)
-> decltype(std::tie(msg.a, msg.str, msg.b, msg.d) = std::tie(args...), void())
{
std::tie(msg.a, msg.str, msg.b, msg.d) = std::tie(args...);
}
template<typename... Args> auto Fill_ProtoA(Msg& msg, overload_priority_low, Args... args)
{
throw std::runtime_error("Should not be called");
}
template<typename... Args>
auto Fill_ProtoB(Msg& msg, overload_priority_high, Args&&...args)
-> decltype(std::tie(msg.d, msg.str) = std::tie(args...), void())
{
std::tie(msg.d, msg.str) = std::tie(args...);
msg.a = 42;
msg.b = 42;
}
template<typename... Args> auto Fill_ProtoB(Msg& msg, overload_priority_low, Args... args)
{
throw std::runtime_error("Should not be called");
}
And then your dispatcher foo:
template<typename T, typename... Args>
void foo(T value, Args... args)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
Msg msg;
msg.proto = value;
switch (value) {
case PROTO_A: Fill_ProtoA(msg, overload_priority_high{}, args...); break;
case PROTO_B: Fill_ProtoB(msg, overload_priority_high{}, args...); break;
default: break;
}
send_msg(msg);
}
Demo

If I have correctly understood your problem, you want to build a variadic template function for which:
first parameter is a protocol number
following parameters can be of different types and aliment a struct
So I assume that you already have defined one struct Msg (depending on T ?) and that you are able to write the function that aliments the struct with one single param using the proto from the struct:
template <typename Arg>
void process(struct Msg& msg, Arg value) {
switch(msg.proto) {
case PROTO_A:
...
}
}
(maybe process(struct Msg<T>& msg, ...) but I leave that for you because you did not say how you process the individual parameters...
You can then write a recursive process version:
template <typename First first, typename... Args>
void process(struct Msg& msg, First first, Args ... args) {
process(msg, first);
if (sizeof...(args) > 0) {
process(msg, args...);
}
}
And your foo function can become:
template<typename T, typename... Args>
void foo(T value, Args... args)
{
cout << __PRETTY_FUNCTION__ << endl;
Msg msg;
msg.proto = value;
process(msg, args);
send_msg(msg);
}

Here's a generalization that might be of use to you. Here the arguments passed can be in any order (even empty). The compiler will deduce which arguments are assigned to which data members of the object in question (if at all).
#include <iostream>
#include <tuple>
#include <string>
constexpr std::size_t NOT_FOUND = -1;
using default_tuple = std::tuple<int, bool, double, char, std::string>;
template <typename, std::size_t> struct Pair;
template <typename Tuple, typename T, std::size_t Start, typename = void>
struct Find : std::integral_constant<std::size_t, NOT_FOUND> {};
template <typename Tuple, typename T, std::size_t Start>
struct Find<Tuple, T, Start, std::enable_if_t<(Start < std::tuple_size<Tuple>::value)>> {
static constexpr size_t value = std::is_same<std::remove_reference_t<T>, std::tuple_element_t<Start, Tuple>>::value ? Start : Find<Tuple, T, Start+1>::value;
};
template <typename T, typename... Pairs> struct SearchPairs;
template <typename T>
struct SearchPairs<T> : std::integral_constant<std::size_t, 0> {};
template <typename T, typename First, typename... Rest>
struct SearchPairs<T, First, Rest...> : SearchPairs<T, Rest...> {};
template <typename T, std::size_t I, typename... Rest>
struct SearchPairs<T, Pair<T,I>, Rest...> : std::integral_constant<std::size_t, I> {};
template <typename Tuple, typename ArgsTuple, std::size_t Start, std::size_t OriginalSize, typename Indices, typename LastIndices, typename = void>
struct ObtainIndices {
using type = Indices;
};
template <typename Tuple1, typename Tuple2, std::size_t Start, std::size_t OriginalSize, std::size_t... Is, typename... Pairs>
struct ObtainIndices<Tuple1, Tuple2, Start, OriginalSize, std::index_sequence<Is...>, std::tuple<Pairs...>,
std::enable_if_t<(Start < std::tuple_size<Tuple2>::value)>> {
using T = std::tuple_element_t<Start, Tuple2>;
static constexpr std::size_t start = SearchPairs<T, Pairs...>::value, // Searching through Pairs..., and will be 0 only if T is not found among the pairs. Else we start after where the last T was found in Tuple1.
index = Find<Tuple1, T, start>::value;
using type = std::conditional_t<(index < OriginalSize),
typename ObtainIndices<Tuple1, Tuple2, Start+1, OriginalSize, std::index_sequence<Is..., index>, std::tuple<Pair<T, index+1>, Pairs...>>::type, // Pair<T, index+1> because we start searching for T again (if ever) after position 'index'. Also, we must place Pair<T, index+1> before the Pairs... pack rather than after it because if a Pair with T already exists, that Pair must not be used again.
typename ObtainIndices<Tuple1, Tuple2, Start+1, OriginalSize, std::index_sequence<Is..., index>, std::tuple<Pair<T, index>, Pairs...>>::type // We add Pair<T, index> right before Pairs... since we want to use the default T value again if another T value is ever needed. Now this could clutter up the std::tuple<Pairs...> pack with many Pairs, causing more compile time, but there is no guarantee that Pair<T, index+1> is already there (since this default T value could be the first T value found).
>;
};
template <std::size_t I, std::size_t J, typename Tuple1, typename Tuple2>
void assignHelper (Tuple1&& tuple1, const Tuple2& tuple2) {
if (std::get<J>(tuple2) != std::tuple_element_t<J, Tuple2>()) // Make the assignment only if the right hand side is not the default value.
std::get<I>(std::forward<Tuple1>(tuple1)) = std::get<J>(tuple2);
}
template <typename Tuple1, typename Tuple2, std::size_t... Is, std::size_t... Js>
void assign (Tuple1&& tuple1, Tuple2&& tuple2, std::index_sequence<Is...>, std::index_sequence<Js...>) {
const int a[] = {(assignHelper<Is, Js>(tuple1, tuple2), 0)...};
static_cast<void>(a);
}
template <typename T, typename... Args>
void fillData (T& t, Args&&... args) {
auto s = t.tuple_ref();
std::tuple<Args...> a = std::tie(args...);
const auto tuple = std::tuple_cat(a, default_tuple{}); // Add default values for each type, in case they are needed if those types are absent in 'a'.
using IndexSequence = typename ObtainIndices<std::remove_const_t<decltype(tuple)>, decltype(s), 0, sizeof...(Args), std::index_sequence<>, std::tuple<>>::type;
assign (s, tuple, std::make_index_sequence<std::tuple_size<decltype(s)>::value>{}, IndexSequence{});
}
// Testing
class Thing {
int a, b;
char c;
double d;
std::string s;
int n;
public:
auto tuple_ref() {return std::tie(a, b, c, d, s, n);} // This (non-const) member function must be defined for any class that wants to be used in the 'fillData' function. Here 'auto' is std::tuple<int&, int&, char&, double&, std::string&, int&>.
void print() const {std::cout << "a = " << a << ", b = " << b << ", c = " << c << ", d = " << d << ", s = " << s << ", n = " << n << '\n';}
};
int main() {
Thing thing;
fillData (thing, 5, 12.8);
thing.print(); // a = 5, b = uninitialized, c = uninitialized, d = 12.8, s = uninitialized, n = uninitialized
fillData (thing, 3.14, 2, 'p', std::string("hi"), 5, 'k', 5.8, 10, std::string("bye"), 9); // Note that std::string("hi") must be use instead of "hi" because "hi" is of type const char[2], not std::string (then the program would not compile). See my thread http://stackoverflow.com/questions/36223914/stdstring-type-lost-in-tuple/36224017#36224006
thing.print(); // a = 2, b = 5, c = p, d = 3.14, s = hi, n = 10
fillData (thing, 4.8, 8, 'q', std::string("hello"));
thing.print(); // a = 8, b = 5, c = q, d = 4.8, s = hello, n = 10
fillData (thing, std::string("game over"));
thing.print(); // a = 8, b = 5, c = q, d = 4.8, s = game over, n = 10
}

Related

Can't get tuple member by its index in a loop [duplicate]

How can I iterate over a tuple (using C++11)? I tried the following:
for(int i=0; i<std::tuple_size<T...>::value; ++i)
std::get<i>(my_tuple).do_sth();
but this doesn't work:
Error 1: sorry, unimplemented: cannot expand ‘Listener ...’ into a fixed-length argument list.
Error 2: i cannot appear in a constant expression.
So, how do I correctly iterate over the elements of a tuple?
I have an answer based on Iterating over a Tuple:
#include <tuple>
#include <utility>
#include <iostream>
template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
print(std::tuple<Tp...>& t)
{ }
template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
print(std::tuple<Tp...>& t)
{
std::cout << std::get<I>(t) << std::endl;
print<I + 1, Tp...>(t);
}
int
main()
{
typedef std::tuple<int, float, double> T;
T t = std::make_tuple(2, 3.14159F, 2345.678);
print(t);
}
The usual idea is to use compile time recursion. In fact, this idea is used to make a printf that is type safe as noted in the original tuple papers.
This can be easily generalized into a for_each for tuples:
#include <tuple>
#include <utility>
template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
for_each(std::tuple<Tp...> &, FuncT) // Unused arguments are given no names.
{ }
template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
for_each(std::tuple<Tp...>& t, FuncT f)
{
f(std::get<I>(t));
for_each<I + 1, FuncT, Tp...>(t, f);
}
Though this then requires some effort to have FuncT represent something with the appropriate overloads for every type the tuple might contain. This works best if you know all the tuple elements will share a common base class or something similar.
In C++17, you can use std::apply with fold expression:
std::apply([](auto&&... args) {((/* args.dosomething() */), ...);}, the_tuple);
A complete example for printing a tuple:
#include <tuple>
#include <iostream>
int main()
{
std::tuple t{42, 'a', 4.2}; // Another C++17 feature: class template argument deduction
std::apply([](auto&&... args) {((std::cout << args << '\n'), ...);}, t);
}
[Online Example on Coliru]
This solution solves the issue of evaluation order in M. Alaggan's answer.
C++ is introducing expansion statements for this purpose. They were originally on track for C++20 but narrowly missed the cut due to a lack of time for language wording review (see here and here).
The currently agreed syntax (see the links above) is:
{
auto tup = std::make_tuple(0, 'a', 3.14);
template for (auto elem : tup)
std::cout << elem << std::endl;
}
Boost.Fusion is a possibility:
Untested example:
struct DoSomething
{
template<typename T>
void operator()(T& t) const
{
t.do_sth();
}
};
tuple<....> t = ...;
boost::fusion::for_each(t, DoSomething());
In C++17 you can do this:
std::apply([](auto ...x){std::make_tuple(x.do_something()...);} , the_tuple);
This already works in Clang++ 3.9, using std::experimental::apply.
A more simple, intuitive and compiler-friendly way of doing this in C++17, using if constexpr:
// prints every element of a tuple
template<size_t I = 0, typename... Tp>
void print(std::tuple<Tp...>& t) {
std::cout << std::get<I>(t) << " ";
// do things
if constexpr(I+1 != sizeof...(Tp))
print<I+1>(t);
}
This is compile-time recursion, similar to the one presented by #emsr. But this doesn't use SFINAE so (I think) it is more compiler-friendly.
Use Boost.Hana and generic lambdas:
#include <tuple>
#include <iostream>
#include <boost/hana.hpp>
#include <boost/hana/ext/std/tuple.hpp>
struct Foo1 {
int foo() const { return 42; }
};
struct Foo2 {
int bar = 0;
int foo() { bar = 24; return bar; }
};
int main() {
using namespace std;
using boost::hana::for_each;
Foo1 foo1;
Foo2 foo2;
for_each(tie(foo1, foo2), [](auto &foo) {
cout << foo.foo() << endl;
});
cout << "foo2.bar after mutation: " << foo2.bar << endl;
}
http://coliru.stacked-crooked.com/a/27b3691f55caf271
Here's an easy C++17 way of iterating over tuple items with just standard library:
#include <tuple> // std::tuple
#include <functional> // std::invoke
template <
size_t Index = 0, // start iteration at 0 index
typename TTuple, // the tuple type
size_t Size =
std::tuple_size_v<
std::remove_reference_t<TTuple>>, // tuple size
typename TCallable, // the callable to be invoked for each tuple item
typename... TArgs // other arguments to be passed to the callable
>
void for_each(TTuple&& tuple, TCallable&& callable, TArgs&&... args)
{
if constexpr (Index < Size)
{
std::invoke(callable, args..., std::get<Index>(tuple));
if constexpr (Index + 1 < Size)
for_each<Index + 1>(
std::forward<TTuple>(tuple),
std::forward<TCallable>(callable),
std::forward<TArgs>(args)...);
}
}
Example:
#include <iostream>
int main()
{
std::tuple<int, char> items{1, 'a'};
for_each(items, [](const auto& item) {
std::cout << item << "\n";
});
}
Output:
1
a
This can be extended to conditionally break the loop in case the callable returns a value (but still work with callables that do not return a bool assignable value, e.g. void):
#include <tuple> // std::tuple
#include <functional> // std::invoke
template <
size_t Index = 0, // start iteration at 0 index
typename TTuple, // the tuple type
size_t Size =
std::tuple_size_v<
std::remove_reference_t<TTuple>>, // tuple size
typename TCallable, // the callable to bo invoked for each tuple item
typename... TArgs // other arguments to be passed to the callable
>
void for_each(TTuple&& tuple, TCallable&& callable, TArgs&&... args)
{
if constexpr (Index < Size)
{
if constexpr (std::is_assignable_v<bool&, std::invoke_result_t<TCallable&&, TArgs&&..., decltype(std::get<Index>(tuple))>>)
{
if (!std::invoke(callable, args..., std::get<Index>(tuple)))
return;
}
else
{
std::invoke(callable, args..., std::get<Index>(tuple));
}
if constexpr (Index + 1 < Size)
for_each<Index + 1>(
std::forward<TTuple>(tuple),
std::forward<TCallable>(callable),
std::forward<TArgs>(args)...);
}
}
Example:
#include <iostream>
int main()
{
std::tuple<int, char> items{ 1, 'a' };
for_each(items, [](const auto& item) {
std::cout << item << "\n";
});
std::cout << "---\n";
for_each(items, [](const auto& item) {
std::cout << item << "\n";
return false;
});
}
Output:
1
a
---
1
You need to use template metaprogramming, here shown with Boost.Tuple:
#include <boost/tuple/tuple.hpp>
#include <iostream>
template <typename T_Tuple, size_t size>
struct print_tuple_helper {
static std::ostream & print( std::ostream & s, const T_Tuple & t ) {
return print_tuple_helper<T_Tuple,size-1>::print( s, t ) << boost::get<size-1>( t );
}
};
template <typename T_Tuple>
struct print_tuple_helper<T_Tuple,0> {
static std::ostream & print( std::ostream & s, const T_Tuple & ) {
return s;
}
};
template <typename T_Tuple>
std::ostream & print_tuple( std::ostream & s, const T_Tuple & t ) {
return print_tuple_helper<T_Tuple,boost::tuples::length<T_Tuple>::value>::print( s, t );
}
int main() {
const boost::tuple<int,char,float,char,double> t( 0, ' ', 2.5f, '\n', 3.1416 );
print_tuple( std::cout, t );
return 0;
}
In C++0x, you can write print_tuple() as a variadic template function instead.
First define some index helpers:
template <size_t ...I>
struct index_sequence {};
template <size_t N, size_t ...I>
struct make_index_sequence : public make_index_sequence<N - 1, N - 1, I...> {};
template <size_t ...I>
struct make_index_sequence<0, I...> : public index_sequence<I...> {};
With your function you would like to apply on each tuple element:
template <typename T>
/* ... */ foo(T t) { /* ... */ }
you can write:
template<typename ...T, size_t ...I>
/* ... */ do_foo_helper(std::tuple<T...> &ts, index_sequence<I...>) {
std::tie(foo(std::get<I>(ts)) ...);
}
template <typename ...T>
/* ... */ do_foo(std::tuple<T...> &ts) {
return do_foo_helper(ts, make_index_sequence<sizeof...(T)>());
}
Or if foo returns void, use
std::tie((foo(std::get<I>(ts)), 1) ... );
Note: On C++14 make_index_sequence is already defined (http://en.cppreference.com/w/cpp/utility/integer_sequence).
If you do need a left-to-right evaluation order, consider something like this:
template <typename T, typename ...R>
void do_foo_iter(T t, R ...r) {
foo(t);
do_foo(r...);
}
void do_foo_iter() {}
template<typename ...T, size_t ...I>
void do_foo_helper(std::tuple<T...> &ts, index_sequence<I...>) {
do_foo_iter(std::get<I>(ts) ...);
}
template <typename ...T>
void do_foo(std::tuple<T...> &ts) {
do_foo_helper(ts, make_index_sequence<sizeof...(T)>());
}
If you want to use std::tuple and you have C++ compiler which supports variadic templates, try code bellow (tested with g++4.5). This should be the answer to your question.
#include <tuple>
// ------------- UTILITY---------------
template<int...> struct index_tuple{};
template<int I, typename IndexTuple, typename... Types>
struct make_indexes_impl;
template<int I, int... Indexes, typename T, typename ... Types>
struct make_indexes_impl<I, index_tuple<Indexes...>, T, Types...>
{
typedef typename make_indexes_impl<I + 1, index_tuple<Indexes..., I>, Types...>::type type;
};
template<int I, int... Indexes>
struct make_indexes_impl<I, index_tuple<Indexes...> >
{
typedef index_tuple<Indexes...> type;
};
template<typename ... Types>
struct make_indexes : make_indexes_impl<0, index_tuple<>, Types...>
{};
// ----------- FOR EACH -----------------
template<typename Func, typename Last>
void for_each_impl(Func&& f, Last&& last)
{
f(last);
}
template<typename Func, typename First, typename ... Rest>
void for_each_impl(Func&& f, First&& first, Rest&&...rest)
{
f(first);
for_each_impl( std::forward<Func>(f), rest...);
}
template<typename Func, int ... Indexes, typename ... Args>
void for_each_helper( Func&& f, index_tuple<Indexes...>, std::tuple<Args...>&& tup)
{
for_each_impl( std::forward<Func>(f), std::forward<Args>(std::get<Indexes>(tup))...);
}
template<typename Func, typename ... Args>
void for_each( std::tuple<Args...>& tup, Func&& f)
{
for_each_helper(std::forward<Func>(f),
typename make_indexes<Args...>::type(),
std::forward<std::tuple<Args...>>(tup) );
}
template<typename Func, typename ... Args>
void for_each( std::tuple<Args...>&& tup, Func&& f)
{
for_each_helper(std::forward<Func>(f),
typename make_indexes<Args...>::type(),
std::forward<std::tuple<Args...>>(tup) );
}
boost::fusion is another option, but it requires its own tuple type: boost::fusion::tuple. Lets better stick to the standard! Here is a test:
#include <iostream>
// ---------- FUNCTOR ----------
struct Functor
{
template<typename T>
void operator()(T& t) const { std::cout << t << std::endl; }
};
int main()
{
for_each( std::make_tuple(2, 0.6, 'c'), Functor() );
return 0;
}
the power of variadic templates!
In MSVC STL there's a _For_each_tuple_element function (not documented):
#include <tuple>
// ...
std::tuple<int, char, float> values{};
std::_For_each_tuple_element(values, [](auto&& value)
{
// process 'value'
});
Another option would be to implement iterators for tuples. This has the advantage that you can use a variety of algorithms provided by the standard library and range-based for loops. An elegant approach to this is explained here https://foonathan.net/2017/03/tuple-iterator/. The basic idea is to turn tuples into a range with begin() and end() methods to provide iterators. The iterator itself returns a std::variant<...> which can then be visited using std::visit.
Here some examples:
auto t = std::tuple{ 1, 2.f, 3.0 };
auto r = to_range(t);
for(auto v : r)
{
std::visit(unwrap([](auto& x)
{
x = 1;
}), v);
}
std::for_each(begin(r), end(r), [](auto v)
{
std::visit(unwrap([](auto& x)
{
x = 0;
}), v);
});
std::accumulate(begin(r), end(r), 0.0, [](auto acc, auto v)
{
return acc + std::visit(unwrap([](auto& x)
{
return static_cast<double>(x);
}), v);
});
std::for_each(begin(r), end(r), [](auto v)
{
std::visit(unwrap([](const auto& x)
{
std::cout << x << std::endl;
}), v);
});
std::for_each(begin(r), end(r), [](auto v)
{
std::visit(overload(
[](int x) { std::cout << "int" << std::endl; },
[](float x) { std::cout << "float" << std::endl; },
[](double x) { std::cout << "double" << std::endl; }), v);
});
My implementation (which is heavily based on the explanations in the link above):
#ifndef TUPLE_RANGE_H
#define TUPLE_RANGE_H
#include <utility>
#include <functional>
#include <variant>
#include <type_traits>
template<typename Accessor>
class tuple_iterator
{
public:
tuple_iterator(Accessor acc, const int idx)
: acc_(acc), index_(idx)
{
}
tuple_iterator operator++()
{
++index_;
return *this;
}
template<typename T>
bool operator ==(tuple_iterator<T> other)
{
return index_ == other.index();
}
template<typename T>
bool operator !=(tuple_iterator<T> other)
{
return index_ != other.index();
}
auto operator*() { return std::invoke(acc_, index_); }
[[nodiscard]] int index() const { return index_; }
private:
const Accessor acc_;
int index_;
};
template<bool IsConst, typename...Ts>
struct tuple_access
{
using tuple_type = std::tuple<Ts...>;
using tuple_ref = std::conditional_t<IsConst, const tuple_type&, tuple_type&>;
template<typename T>
using element_ref = std::conditional_t<IsConst,
std::reference_wrapper<const T>,
std::reference_wrapper<T>>;
using variant_type = std::variant<element_ref<Ts>...>;
using function_type = variant_type(*)(tuple_ref);
using table_type = std::array<function_type, sizeof...(Ts)>;
private:
template<size_t Index>
static constexpr function_type create_accessor()
{
return { [](tuple_ref t) -> variant_type
{
if constexpr (IsConst)
return std::cref(std::get<Index>(t));
else
return std::ref(std::get<Index>(t));
} };
}
template<size_t...Is>
static constexpr table_type create_table(std::index_sequence<Is...>)
{
return { create_accessor<Is>()... };
}
public:
static constexpr auto table = create_table(std::make_index_sequence<sizeof...(Ts)>{});
};
template<bool IsConst, typename...Ts>
class tuple_range
{
public:
using tuple_access_type = tuple_access<IsConst, Ts...>;
using tuple_ref = typename tuple_access_type::tuple_ref;
static constexpr auto tuple_size = sizeof...(Ts);
explicit tuple_range(tuple_ref tuple)
: tuple_(tuple)
{
}
[[nodiscard]] auto begin() const
{
return tuple_iterator{ create_accessor(), 0 };
}
[[nodiscard]] auto end() const
{
return tuple_iterator{ create_accessor(), tuple_size };
}
private:
tuple_ref tuple_;
auto create_accessor() const
{
return [this](int idx)
{
return std::invoke(tuple_access_type::table[idx], tuple_);
};
}
};
template<bool IsConst, typename...Ts>
auto begin(const tuple_range<IsConst, Ts...>& r)
{
return r.begin();
}
template<bool IsConst, typename...Ts>
auto end(const tuple_range<IsConst, Ts...>& r)
{
return r.end();
}
template <class ... Fs>
struct overload : Fs... {
explicit overload(Fs&&... fs) : Fs{ fs }... {}
using Fs::operator()...;
template<class T>
auto operator()(std::reference_wrapper<T> ref)
{
return (*this)(ref.get());
}
template<class T>
auto operator()(std::reference_wrapper<const T> ref)
{
return (*this)(ref.get());
}
};
template <class F>
struct unwrap : overload<F>
{
explicit unwrap(F&& f) : overload<F>{ std::forward<F>(f) } {}
using overload<F>::operator();
};
template<typename...Ts>
auto to_range(std::tuple<Ts...>& t)
{
return tuple_range<false, Ts...>{t};
}
template<typename...Ts>
auto to_range(const std::tuple<Ts...>& t)
{
return tuple_range<true, Ts...>{t};
}
#endif
Read-only access is also supported by passing a const std::tuple<>& to to_range().
Others have mentioned some well-designed third-party libraries that you may turn to. However, if you are using C++ without those third-party libraries, the following code may help.
namespace detail {
template <class Tuple, std::size_t I, class = void>
struct for_each_in_tuple_helper {
template <class UnaryFunction>
static void apply(Tuple&& tp, UnaryFunction& f) {
f(std::get<I>(std::forward<Tuple>(tp)));
for_each_in_tuple_helper<Tuple, I + 1u>::apply(std::forward<Tuple>(tp), f);
}
};
template <class Tuple, std::size_t I>
struct for_each_in_tuple_helper<Tuple, I, typename std::enable_if<
I == std::tuple_size<typename std::decay<Tuple>::type>::value>::type> {
template <class UnaryFunction>
static void apply(Tuple&&, UnaryFunction&) {}
};
} // namespace detail
template <class Tuple, class UnaryFunction>
UnaryFunction for_each_in_tuple(Tuple&& tp, UnaryFunction f) {
detail::for_each_in_tuple_helper<Tuple, 0u>
::apply(std::forward<Tuple>(tp), f);
return std::move(f);
}
Note: The code compiles with any compiler supporing C++11, and it keeps consistency with design of the standard library:
The tuple need not be std::tuple, and instead may be anything that supports std::get and std::tuple_size; in particular, std::array and std::pair may be used;
The tuple may be a reference type or cv-qualified;
It has similar behavior as std::for_each, and returns the input UnaryFunction;
For C++14 (or laster version) users, typename std::enable_if<T>::type and typename std::decay<T>::type could be replaced with their simplified version, std::enable_if_t<T> and std::decay_t<T>;
For C++17 (or laster version) users, std::tuple_size<T>::value could be replaced with its simplified version, std::tuple_size_v<T>.
For C++20 (or laster version) users, the SFINAE feature could be implemented with the Concepts.
Using constexpr and if constexpr(C++17) this is fairly simple and straight forward:
template <std::size_t I = 0, typename ... Ts>
void print(std::tuple<Ts...> tup) {
if constexpr (I == sizeof...(Ts)) {
return;
} else {
std::cout << std::get<I>(tup) << ' ';
print<I+1>(tup);
}
}
I might have missed this train, but this will be here for future reference.
Here's my construct based on this answer and on this gist:
#include <tuple>
#include <utility>
template<std::size_t N>
struct tuple_functor
{
template<typename T, typename F>
static void run(std::size_t i, T&& t, F&& f)
{
const std::size_t I = (N - 1);
switch(i)
{
case I:
std::forward<F>(f)(std::get<I>(std::forward<T>(t)));
break;
default:
tuple_functor<I>::run(i, std::forward<T>(t), std::forward<F>(f));
}
}
};
template<>
struct tuple_functor<0>
{
template<typename T, typename F>
static void run(std::size_t, T, F){}
};
You then use it as follow:
template<typename... T>
void logger(std::string format, T... args) //behaves like C#'s String.Format()
{
auto tp = std::forward_as_tuple(args...);
auto fc = [](const auto& t){std::cout << t;};
/* ... */
std::size_t some_index = ...
tuple_functor<sizeof...(T)>::run(some_index, tp, fc);
/* ... */
}
There could be room for improvements.
As per OP's code, it would become this:
const std::size_t num = sizeof...(T);
auto my_tuple = std::forward_as_tuple(t...);
auto do_sth = [](const auto& elem){/* ... */};
for(int i = 0; i < num; ++i)
tuple_functor<num>::run(i, my_tuple, do_sth);
Of all the answers I've seen here, here and here, I liked #sigidagi's way of iterating best. Unfortunately, his answer is very verbose which in my opinion obscures the inherent clarity.
This is my version of his solution which is more concise and works with std::tuple, std::pair and std::array.
template<typename UnaryFunction>
void invoke_with_arg(UnaryFunction)
{}
/**
* Invoke the unary function with each of the arguments in turn.
*/
template<typename UnaryFunction, typename Arg0, typename... Args>
void invoke_with_arg(UnaryFunction f, Arg0&& a0, Args&&... as)
{
f(std::forward<Arg0>(a0));
invoke_with_arg(std::move(f), std::forward<Args>(as)...);
}
template<typename Tuple, typename UnaryFunction, std::size_t... Indices>
void for_each_helper(Tuple&& t, UnaryFunction f, std::index_sequence<Indices...>)
{
using std::get;
invoke_with_arg(std::move(f), get<Indices>(std::forward<Tuple>(t))...);
}
/**
* Invoke the unary function for each of the elements of the tuple.
*/
template<typename Tuple, typename UnaryFunction>
void for_each(Tuple&& t, UnaryFunction f)
{
using size = std::tuple_size<typename std::remove_reference<Tuple>::type>;
for_each_helper(
std::forward<Tuple>(t),
std::move(f),
std::make_index_sequence<size::value>()
);
}
Demo: coliru
C++14's std::make_index_sequence can be implemented for C++11.
Expanding on #Stypox answer, we can make their solution more generic (C++17 onward). By adding a callable function argument:
template<size_t I = 0, typename... Tp, typename F>
void for_each_apply(std::tuple<Tp...>& t, F &&f) {
f(std::get<I>(t));
if constexpr(I+1 != sizeof...(Tp)) {
for_each_apply<I+1>(t, std::forward<F>(f));
}
}
Then, we need a strategy to visit each type.
Let start with some helpers (first two taken from cppreference):
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
template<class ... Ts> struct variant_ref { using type = std::variant<std::reference_wrapper<Ts>...>; };
variant_ref is used to allow tuples' state to be modified.
Usage:
std::tuple<Foo, Bar, Foo> tuples;
for_each_apply(tuples,
[](variant_ref<Foo, Bar>::type &&v) {
std::visit(overloaded {
[](Foo &arg) { arg.foo(); },
[](Bar const &arg) { arg.bar(); },
}, v);
});
Result:
Foo0
Bar
Foo0
Foo1
Bar
Foo1
For completeness, here are my Bar & Foo:
struct Foo {
void foo() {std::cout << "Foo" << i++ << std::endl;}
int i = 0;
};
struct Bar {
void bar() const {std::cout << "Bar" << std::endl;}
};
I have stumbled on the same problem for iterating over a tuple of function objects, so here is one more solution:
#include <tuple>
#include <iostream>
// Function objects
class A
{
public:
inline void operator()() const { std::cout << "A\n"; };
};
class B
{
public:
inline void operator()() const { std::cout << "B\n"; };
};
class C
{
public:
inline void operator()() const { std::cout << "C\n"; };
};
class D
{
public:
inline void operator()() const { std::cout << "D\n"; };
};
// Call iterator using recursion.
template<typename Fobjects, int N = 0>
struct call_functors
{
static void apply(Fobjects const& funcs)
{
std::get<N>(funcs)();
// Choose either the stopper or descend further,
// depending if N + 1 < size of the tuple.
using caller = std::conditional_t
<
N + 1 < std::tuple_size_v<Fobjects>,
call_functors<Fobjects, N + 1>,
call_functors<Fobjects, -1>
>;
caller::apply(funcs);
}
};
// Stopper.
template<typename Fobjects>
struct call_functors<Fobjects, -1>
{
static void apply(Fobjects const& funcs)
{
}
};
// Call dispatch function.
template<typename Fobjects>
void call(Fobjects const& funcs)
{
call_functors<Fobjects>::apply(funcs);
};
using namespace std;
int main()
{
using Tuple = tuple<A,B,C,D>;
Tuple functors = {A{}, B{}, C{}, D{}};
call(functors);
return 0;
}
Output:
A
B
C
D
There're many great answers, but for some reason most of them don't consider returning the results of applying f to our tuple...
or did I overlook it? Anyway, here's yet another way you can do that:
Doing Foreach with style (debatable)
auto t = std::make_tuple(1, "two", 3.f);
t | foreach([](auto v){ std::cout << v << " "; });
And returning from that:
auto t = std::make_tuple(1, "two", 3.f);
auto sizes = t | foreach([](auto v) {
return sizeof(v);
});
sizes | foreach([](auto v) {
std::cout << v;
});
Implementation (pretty simple one)
Edit: it gets a little messier.
I won't include some metaprogramming boilerplate here, for it will definitely make things less readable and besides, I believe those have already been answered somewhere on stackoverflow.
In case you're feeling lazy, feel free to peek into my github repo for implementation of both
#include <utility>
// Optional includes, if you don't want to implement it by hand or google it
// you can find it in the repo (link below)
#include "typesystem/typelist.hpp"
// used to check if all return types are void,
// making it a special case
// (and, alas, not using constexpr-if
// for the sake of being compatible with C++14...)
template <bool Cond, typename T, typename F>
using select = typename std::conditional<Cond, T, F>::type;
template <typename F>
struct elementwise_apply {
F f;
};
template <typename F>
constexpr auto foreach(F && f) -> elementwise_apply<F> { return {std::forward<F>(f)}; }
template <typename R>
struct tuple_map {
template <typename F, typename T, size_t... Is>
static constexpr decltype(auto) impl(std::index_sequence<Is...>, F && f, T&& tuple) {
return R{ std::forward<F>(f)( std::get<Is>(tuple) )... };
}
};
template<>
struct tuple_map<void> {
template <typename F, typename T, size_t... Is>
static constexpr void impl(std::index_sequence<Is...>, F && f, T&& tuple) {
[[maybe_unused]] std::initializer_list<int> _ {((void)std::forward<F>(f)( std::get<Is>(tuple) ), 0)... };
}
};
template <typename F, typename... Ts>
constexpr decltype(auto) operator| (std::tuple<Ts...> & t, fmap<F> && op) {
constexpr bool all_void = core::Types<decltype( std::move(op).f(std::declval<Ts&>()) )...>.all( core::is_void );
using R = meta::select<all_void, void, std::tuple<decltype(std::move(op).f(std::declval<Ts&>()))...>>;
return tuple_map<R>::impl(std::make_index_sequence<sizeof...(Ts)>{}, std::move(op).f, t);
}
template <typename F, typename... Ts>
constexpr decltype(auto) operator| (std::tuple<Ts...> const& t, fmap<F> && op) {
constexpr bool all_void = check if all "decltype( std::move(op).f(std::declval<Ts>()) )..." types are void, since then it's a special case
// e.g. core::Types<decltype( std::move(op).f(std::declval<Ts>()) )...>.all( core::is_void );
using R = meta::select<all_void, void, std::tuple<decltype(std::move(op).f(std::declval<Ts const&>()))...>>;
return tuple_map<R>::impl(std::make_index_sequence<sizeof...(Ts)>{}, std::move(op).f, t);
}
template <typename F, typename... Ts>
constexpr decltype(auto) operator| (std::tuple<Ts...> && t, fmap<F> && op) {
constexpr bool all_void = core::Types<decltype( std::move(op).f(std::declval<Ts&&>()) )...>.all( core::is_void );
using R = meta::select<all_void, void, std::tuple<decltype(std::move(op).f(std::declval<Ts&&>()))...>>;
return tuple_map<R>::impl(std::make_index_sequence<sizeof...(Ts)>{}, std::move(op).f, std::move(t));
}
Yeah, that would be much nicer if we were to use C++17
This is also an example of std::moving object's members, for which I'll better refer to this nice brief article
P.S. If you're stuck checking if all "decltype( std::move(op).f(std::declval()) )..." types are void
you can find some metaprogramming library, or, if those libraries seem too hard to grasp (which some of them may be due to some crazy metaprogramming tricks), you know where to look
template <typename F, typename T>
static constexpr size_t
foreach_in_tuple(std::tuple<T> & tuple, F && do_, size_t index_ = 0)
{
do_(tuple, index_);
return index_;
}
template <typename F, typename T, typename U, typename... Types>
static constexpr size_t
foreach_in_tuple(std::tuple<T,U,Types...> & tuple, F && do_, size_t index_ = 0)
{
if(!do_(tuple, index_))
return index_;
auto & next_tuple = reinterpret_cast<std::tuple<U,Types...> &>(tuple);
return foreach_in_tuple(next_tuple, std::forward<F>(do_), index_+1);
}
int main()
{
using namespace std;
auto tup = make_tuple(1, 2.3f, 'G', "hello");
foreach_in_tuple(tup, [](auto & tuple, size_t i)
{
auto & value = std::get<0>(tuple);
std::cout << i << " " << value << std::endl;
// if(i >= 2) return false; // break;
return true; // continue
});
}
Here is a solution based on std::interger_sequence.
As I don't know if my_tuple is constructed from std::make_tuple<T>(T &&...) in your code. It's essential for how to construct std::integer_sequence in the solution below.
(1) if your already have a my_tuple outside your function(not using template<typename ...T>), You can use
[](auto my_tuple)
{
[&my_tuple]<typename N, N... n>(std::integer_sequence<N, n...> int_seq)
{
((std::cout << std::get<n>(my_tuple) << '\n'), ...);
}(std::make_index_sequence<std::tuple_size_v<decltype(my_tuple)>>{});
}(std::make_tuple());
(2) if your havn't constructed my_tuple in your function and want to handle your T ...arguments
[]<typename ...T>(T... args)
{
[&args...]<typename N, N... n>(std::integer_sequence<N, n...> int_seq)
{
((std::cout << std::get<n>(std::forward_as_tuple(args...)) << '\n'), ...);
}(std::index_sequence_for<T...>{});
}();
boost's tuple provides helper functions get_head() and get_tail() so your helper functions may look like this:
inline void call_do_sth(const null_type&) {};
template <class H, class T>
inline void call_do_sth(cons<H, T>& x) { x.get_head().do_sth(); call_do_sth(x.get_tail()); }
as described in here http://www.boost.org/doc/libs/1_34_0/libs/tuple/doc/tuple_advanced_interface.html
with std::tuple it should be similar.
Actually, unfortunately std::tuple does not seem to provide such interface, so methods suggested before should work, or you would need to switch to boost::tuple which has other benefits (like io operators already provided). Though there is downside of boost::tuple with gcc - it does not accept variadic templates yet, but that may be already fixed as I do not have latest version of boost installed on my machine.

Using type traits on template parameter packs?

In bellow sample code I'm trying to check if function arguments are pointers or not with std::is_pointer
it works fine if there is only one parameter, but how to make it work with more parameters, such as in parameter pack?
#include <type_traits>
#include <iostream>
class Test
{
public:
template<typename... Params>
void f(Params... params);
template<typename T, typename... Params>
auto sum(T arg, Params... params)
{
return arg + sum(params...);
}
template<typename T>
auto sum(T arg)
{
return arg;
}
int member = 1;
};
template<typename... Params>
void Test::f(Params... params)
{
// ERROR: too many template arguments for std::is_pointer
if constexpr (std::is_pointer_v<Params...>)
member += sum(*params...);
else
member += sum(params...);
std::cout << member;
}
int main()
{
Test ts;
// both fail
ts.f(1, 2);
ts.f(&ts.member, &ts.member);
// is that even possible?
ts.f(&ts.member, 2);
return 0;
}
I guess if parameters are not either all pointers or all not pointers then we have additional issue, but let's just assume all arguments are either pointers or not.
then what about if arguments are mix of pointers and non pointers anyway?
You can use a fold expression:
#include <iostream>
#include <type_traits>
template <typename... Ts>
void test(Ts... ts) {
if constexpr ((std::is_pointer_v<Ts> && ...)) {
std::cout << "yes\n";
} else {
std::cout << "no\n";
}
}
int main() {
test(new int, new char, new int);
test(new int, new char, new int, 2);
}
The output of the program:
yes
no
Be careful with your function template signature though - I would advise using Ts&&... ts instead of Ts... ts, because of how const char[]s are treated. With my original example, test(new int, new char, new int, "hello"); will yield a yes output, but with Ts&&... ts, it will yield no.
For anyone using C++11/14, you can use the following solution.
// helper struct that checks the list
template<int N, typename... Args>
struct is_all_pointer_helper;
// N > 1, checks the head and recursively checks the tail
template<int N, typename Arg, typename... Args>
struct is_all_pointer_helper<N, Arg, Args...> {
static constexpr bool value =
std::is_pointer<Arg>::value &&
is_all_pointer_helper<N-1, Args...>::value;
};
// N == 1, checks the head (end of recursion)
template<typename Arg, typename... Args>
struct is_all_pointer_helper<1, Arg, Args...> {
static constexpr bool value = std::is_pointer<Arg>::value;
};
// N == 0, define your result for the empty list
template<> struct is_all_pointer_helper<0> {
static constexpr bool value = false;
};
// user interface
template<typename... Args>
struct is_all_pointer : is_all_pointer_helper<sizeof...(Args), Args...> {};
// C++14 only
template<typename... Args>
constexpr bool is_all_pointer_v = is_all_pointer<Args...>::value;
class Foo {};
int main()
{
cout << std::boolalpha << is_all_pointer<int*, char*, Foo*>::value << endl;
cout << std::boolalpha << is_all_pointer_v<int*, char, Foo*> << endl; //C++14
cout << std::boolalpha << is_all_pointer<>::value << endl;
}
Output:
true
false
false
The problem can be simplified (and the program made to work) by moving the detection of whether a param is a pointer into the variadic template function sum.
example:
#include <type_traits>
#include <iostream>
class Test
{
public:
template<typename... Params>
void f(Params... params)
{
member += sum(params...);
std::cout << member << '\n';
}
template<typename... Params>
auto sum(Params... params)
{
auto contents = [](auto param)
{
using ParamType = std::decay_t<decltype(param)>;
if constexpr (std::is_pointer_v<ParamType>)
return *param;
else
return param;
};
return (contents(params) + ...);
}
int member = 1;
};
int main()
{
Test ts;
// both fail
ts.f(1, 2);
ts.f(&ts.member, &ts.member);
// is that even possible?
ts.f(&ts.member, 2);
return 0;
}
Expected output:
4
12
26
https://godbolt.org/z/y57-TA

Workaround for passing variadic arguments to lambda expression if compiler does not support it

I have two solutions, both work as I expect but the first one
works only with newer version of GCC (5.2.1 for sure) and the second one works in GCC >= 4.8.3. The problem is that at my work I unfortunately do not have access to newer version of GCC.
The first solution is basically what I wanted by the behavior and by the level of complexity. The second one also works but this is the ugliest thing I have ever written and to be honest I do not know if this is the correct code (but it works).
Ok, firstly I will describe the problem that I am facing:
I have a function called logic() here, which takes callable object to invoke some additional logic among other instructions. These instructions of course are not here, because they are not necessary, they are marked as (X).
template <typename C>
void logic (C c) {
// before callable actions (X)
c ();
// after callable actions (X)
}
What I want to do as the callable object is to set some bool value(s) using appropriate type(s) - set_single() function. For the example I will use some additional types:
struct P1 {};
struct P2 {};
struct P3 {};
Consider first solution:
namespace Solution1 {
template <typename T>
void set_single (bool c) {
// use type T to set c value - details are not the case here.
std::cout << "value = " << c << std::endl;
std::cout << "P1 = " << std::is_same<T, P1>::value << std::endl;
std::cout << "P2 = " << std::is_same<T, P2>::value << std::endl;
std::cout << "P3 = " << std::is_same<T, P3>::value << std::endl;
}
template <typename T, typename K, typename... Ts, typename... Vs>
void set_single (bool t, bool k, Vs&&... args) {
set_single<T> (t);
set_single<K, Ts...> (k, std::forward<Vs> (args)...);
}
template <typename... Ts, typename... Args>
void set (Args&&... args) {
static_assert (sizeof... (Ts) == sizeof... (Args), "");
logic ([&] () {
set_single<Ts...> (std::forward<Args> (args)...);
});
}
}
set() function is a wrapper and it is public for the user, set_single() are implementation details so they are hidden (for simplicity they are not written in a class).
So, passing callable object to logic() function inside set() function I invoke set_single() function arbitrary number of times passing all the values with corresponding types that I need. So, for example, usage could be like this:
Solution1::set<P1, P2, P3> (true, false, true);
and this will use type P1 to set true, type P2 to set false and type P3 to set true.
So, here we have a solution when your compiler does not support passing variadic arguments to lambda expression.
namespace Solution2 {
template <typename... Ts>
struct X {
X () = default;
X (Ts... t) : tup {std::make_tuple (t...)} {}
std::tuple<Ts...> tup;
};
template <int...>
struct Ints {};
template <int N, int... Is>
struct Int_seq : Int_seq<N-1, N, Is...> {};
template <int... Is>
struct Int_seq<0, Is...> {
using type = Ints<0, Is...>;
};
template <int... Is>
using Iseq = typename Int_seq<Is...>::type;
template <int I, typename... Args, typename... Types>
void set_single (Ints<I>, const std::tuple<Args...>& a, const std::tuple<Types...>& t) {
std::cout << "value = " << std::get<I> (a) << std::endl;
auto p1 = std::get<I> (t);
auto p2 = std::get<I> (t);
auto p3 = std::get<I> (t);
std::cout << "P1 = " << std::is_same<P1, decltype (p1)>::value << std::endl;
std::cout << "P2 = " << std::is_same<P2, decltype (p2)>::value << std::endl;
std::cout << "P3 = " << std::is_same<P3, decltype (p3)>::value << std::endl;
}
template <int I, int K, int... Is, typename... Args, typename... Types>
void set_single (Ints<I, K, Is...>, const std::tuple<Args...>& a, const std::tuple<Types...>& t) {
set_single (Ints<I> {}, a, t);
set_single (Ints<K, Is...> {}, a, t);
}
template <typename... Ts, typename... Args>
void set (Args... args) {
static_assert (sizeof... (Ts) == sizeof... (Args), "");
X<Ts...> types {};
X<Args...> arguments {args...};
logic ([&types, &arguments] () {
set_single (Iseq<std::tuple_size<decltype (arguments.tup)>::value-1> {}, arguments.tup, types.tup);
});
}
}
I used type Solution2::X to store values and types. I tried to do some std::bind() stuff, but it was painful, so I used
some integer sequence (which probably implementation is rather poor). Like I said, both solutions work but the second one is not so cool like the first one.
Could any of you tell me if Solution2 can be replaced by some kind of easier solution? I am pretty sure that some exists.
And usage with output looks like:
Solution1::set<P1, P2, P3> (true, false, true);
value = 1
P1 = 1
P2 = 0
P3 = 0
value = 0
P1 = 0
P2 = 1
P3 = 0
value = 1
P1 = 0
P2 = 0
P3 = 1
Solution2::set<P1, P2, P3> (true, false, true);
value = 1
P1 = 1
P2 = 0
P3 = 0
value = 0
P1 = 0
P2 = 1
P3 = 0
value = 1
P1 = 0
P2 = 0
P3 = 1
You need to use some tagging to keep the given type, as they might not be default constructible.
I would implement that way:
#if 1 // Not in C++11 // make_index_sequence
#include <cstdint>
template <std::size_t...> struct index_sequence {};
template <std::size_t N, std::size_t... Is>
struct make_index_sequence : make_index_sequence<N - 1, N - 1, Is...> {};
template <std::size_t... Is>
struct make_index_sequence<0u, Is...> : index_sequence<Is...> {};
#endif // make_index_sequence
#if 1 // Not in C++11 // tuple_element_t
template <std::size_t I, typename T>
using tuple_element_t = typename std::tuple_element<I, T>::type;
#endif
namespace Solution3 {
template <typename T>
struct bool_impl {
using type = bool;
};
template <typename T>
using bool_t = typename bool_impl<T>::type; // or simply using bool_t = bool
template <typename T>
void set_single (bool c) {
// use type T to set c value - details are not the case here.
std::cout << "value = " << c << std::endl;
std::cout << "P1 = " << std::is_same<T, P1>::value << std::endl;
std::cout << "P2 = " << std::is_same<T, P2>::value << std::endl;
std::cout << "P3 = " << std::is_same<T, P3>::value << std::endl;
}
template <typename T> struct Tag {};
template <typename T1, typename T2, std::size_t ... Is>
void set_singles (Tag<T1>, T2 t, index_sequence<Is...>) {
int dummy[] = {0, (set_single<tuple_element_t<Is, T1>>(std::get<Is>(t)), 0)...};
static_cast<void>(dummy); // Avoid warning for unused variable
}
template <typename... Ts>
void set (bool_t<Ts>... args) {
Tag<std::tuple<Ts...>> tag;
auto bools = std::make_tuple(args...);
auto seq = make_index_sequence<sizeof...(Ts)>();
logic ([&]() {
set_singles(tag, bools, seq);
});
}
}
Demo
And a version simplified for up to date compiler
Demo

Variadic template, get function arguments value

My problem is the following:
I have a class declared as such:
template<typename ReturnType, typename... Args>
class API
{
ReturnType operator()(Args... args)
{
// Get argument 0
// Get argument 1
}
};
I am in need of getting the arguments on by one, and so far the only way I've come up to (but I can not get it to work) is using std::get, as such:
std::get<0>(args);
Of course, this leads to a lot of errors.
I am new to variadic templates (and to C++11 at all) so I am quite lost at this point.
How could I get those arguments one by one?
Any help will be appreciated.
Capture the args in a temporary tuple (Live at Coliru):
ReturnType operator()(Args... args)
{
static_assert(sizeof...(args) >= 3, "Uh-oh, too few args.");
// Capture args in a tuple
auto&& t = std::forward_as_tuple(args...);
// Get argument 0
std::cout << std::get<0>(t) << '\n';
// Get argument 1
std::cout << std::get<1>(t) << '\n';
// Get argument 2
std::cout << std::get<2>(t) << '\n';
}
std::forward_as_tuple uses perfect forwarding to capture references to the args, so there should be no copying.
You can use recursion.
Here's an example:
#include <iostream>
template<typename ReturnType>
class API {
public:
template<typename Arg>
ReturnType operator()(Arg&& arg) {
// do something with arg
return (ReturnType) arg;
}
template<typename Head, typename... Tail>
ReturnType operator()(Head&& head, Tail&&... tail) {
// do something with return values
auto temp = operator()(std::forward<Head>(head));
return temp + operator()(std::forward<Tail>(tail)...);
}
};
int main() {
API<int> api;
auto foo = api(1, 2l, 2.0f);
std::cout << foo;
return 0;
}
A few helper templates can do that for you. I'm not aware of one in stl that does it directly, but I like to roll my own templates anyways:
namespace Internal {
template <size_t Pos, typename Arg, typename... Args>
struct Unpacker {
static auto unpack(Arg&&, Args&&... args) {
return Unpacker<Pos - 1, Args...>::unpack(std::forward<Args>(args)...);
}
};
template <typename Arg, typename... Args>
struct Unpacker<0, Arg, Args...> {
static auto unpack(Arg&& arg, Args&&...) { return std::forward<Arg>(arg); }
};
} // Internal
template <size_t Pos, typename... Args>
auto unpack(Args&&... args) {
return Internal::Unpacker<Pos, Args...>::unpack(std::forward<Args>(args)...);
}
Then you can use it like this:
auto unpacked0 = unpack<0>(1, "orange", 3.3f, "pie");
auto unpacked1 = unpack<1>(1, "orange", 3.3f, "pie");
auto unpacked2 = unpack<2>(1, "orange", 3.3f, "pie");
auto unpacked3 = unpack<3>(1, "orange", 3.3f, "pie");
// Will not compile, because there are only 4 arguments
// auto unpacked4 = unpack<4>(1, "orange", 3.3f, "pie");
fmt::print("{} {} {} {}\n", unpacked0, unpacked1, unpacked2, unpacked3);
Or in your case:
template<typename ReturnType, typename... Args>
class API {
ReturnType operator()(Args&&... args) {
// Get argument 0
auto& arg0 = unpack<0>(args...);
// Get argument 1
auto& arg1 = unpack<1>(args...);
}
};

Apply function from std::tuple [duplicate]

I'm trying to store in a std::tuple a varying number of values, which will later be used as arguments for a call to a function pointer which matches the stored types.
I've created a simplified example showing the problem I'm struggling to solve:
#include <iostream>
#include <tuple>
void f(int a, double b, void* c) {
std::cout << a << ":" << b << ":" << c << std::endl;
}
template <typename ...Args>
struct save_it_for_later {
std::tuple<Args...> params;
void (*func)(Args...);
void delayed_dispatch() {
// How can I "unpack" params to call func?
func(std::get<0>(params), std::get<1>(params), std::get<2>(params));
// But I *really* don't want to write 20 versions of dispatch so I'd rather
// write something like:
func(params...); // Not legal
}
};
int main() {
int a=666;
double b = -1.234;
void *c = NULL;
save_it_for_later<int,double,void*> saved = {
std::tuple<int,double,void*>(a,b,c), f};
saved.delayed_dispatch();
}
Normally for problems involving std::tuple or variadic templates I'd write another template like template <typename Head, typename ...Tail> to recursively evaluate all of the types one by one, but I can't see a way of doing that for dispatching a function call.
The real motivation for this is somewhat more complex and it's mostly just a learning exercise anyway. You can assume that I'm handed the tuple by contract from another interface, so can't be changed but that the desire to unpack it into a function call is mine. This rules out using std::bind as a cheap way to sidestep the underlying problem.
What's a clean way of dispatching the call using the std::tuple, or an alternative better way of achieving the same net result of storing/forwarding some values and a function pointer until an arbitrary future point?
You need to build a parameter pack of numbers and unpack them
template<int ...>
struct seq { };
template<int N, int ...S>
struct gens : gens<N-1, N-1, S...> { };
template<int ...S>
struct gens<0, S...> {
typedef seq<S...> type;
};
// ...
void delayed_dispatch() {
callFunc(typename gens<sizeof...(Args)>::type());
}
template<int ...S>
void callFunc(seq<S...>) {
func(std::get<S>(params) ...);
}
// ...
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
This is a complete compilable version of Johannes' solution to awoodland's question, in the hope it may be useful to somebody. This was tested with a snapshot of g++ 4.7 on Debian squeeze.
###################
johannes.cc
###################
#include <tuple>
#include <iostream>
using std::cout;
using std::endl;
template<int ...> struct seq {};
template<int N, int ...S> struct gens : gens<N-1, N-1, S...> {};
template<int ...S> struct gens<0, S...>{ typedef seq<S...> type; };
double foo(int x, float y, double z)
{
return x + y + z;
}
template <typename ...Args>
struct save_it_for_later
{
std::tuple<Args...> params;
double (*func)(Args...);
double delayed_dispatch()
{
return callFunc(typename gens<sizeof...(Args)>::type());
}
template<int ...S>
double callFunc(seq<S...>)
{
return func(std::get<S>(params) ...);
}
};
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-variable"
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
int main(void)
{
gens<10> g;
gens<10>::type s;
std::tuple<int, float, double> t = std::make_tuple(1, 1.2, 5);
save_it_for_later<int,float, double> saved = {t, foo};
cout << saved.delayed_dispatch() << endl;
}
#pragma GCC diagnostic pop
One can use the following SConstruct file
#####################
SConstruct
#####################
#!/usr/bin/python
env = Environment(CXX="g++-4.7", CXXFLAGS="-Wall -Werror -g -O3 -std=c++11")
env.Program(target="johannes", source=["johannes.cc"])
On my machine, this gives
g++-4.7 -o johannes.o -c -Wall -Werror -g -O3 -std=c++11 johannes.cc
g++-4.7 -o johannes johannes.o
Here is a C++14 solution.
template <typename ...Args>
struct save_it_for_later
{
std::tuple<Args...> params;
void (*func)(Args...);
template<std::size_t ...I>
void call_func(std::index_sequence<I...>)
{ func(std::get<I>(params)...); }
void delayed_dispatch()
{ call_func(std::index_sequence_for<Args...>{}); }
};
This still needs one helper function (call_func). Since this is a common idiom, perhaps the standard should support it directly as std::call with possible implementation
// helper class
template<typename R, template<typename...> class Params, typename... Args, std::size_t... I>
R call_helper(std::function<R(Args...)> const&func, Params<Args...> const&params, std::index_sequence<I...>)
{ return func(std::get<I>(params)...); }
// "return func(params...)"
template<typename R, template<typename...> class Params, typename... Args>
R call(std::function<R(Args...)> const&func, Params<Args...> const&params)
{ return call_helper(func,params,std::index_sequence_for<Args...>{}); }
Then our delayed dispatch becomes
template <typename ...Args>
struct save_it_for_later
{
std::tuple<Args...> params;
std::function<void(Args...)> func;
void delayed_dispatch()
{ std::call(func,params); }
};
This is a bit complicated to achieve (even though it is possible). I advise you to use a library where this is already implemented, namely Boost.Fusion (the invoke function). As a bonus, Boost Fusion works with C++03 compilers as well.
c++14 solution. First, some utility boilerplate:
template<std::size_t...Is>
auto index_over(std::index_sequence<Is...>){
return [](auto&&f)->decltype(auto){
return decltype(f)(f)( std::integral_constant<std::size_t, Is>{}... );
};
}
template<std::size_t N>
auto index_upto(std::integral_constant<std::size_t, N> ={}){
return index_over( std::make_index_sequence<N>{} );
}
These let you call a lambda with a series of compile-time integers.
void delayed_dispatch() {
auto indexer = index_upto<sizeof...(Args)>();
indexer([&](auto...Is){
func(std::get<Is>(params)...);
});
}
and we are done.
index_upto and index_over let you work with parameter packs without having to generate a new external overloads.
Of course, in c++17 you just
void delayed_dispatch() {
std::apply( func, params );
}
Now, if we like that, in c++14 we can write:
namespace notstd {
template<class T>
constexpr auto tuple_size_v = std::tuple_size<T>::value;
template<class F, class Tuple>
decltype(auto) apply( F&& f, Tuple&& tup ) {
auto indexer = index_upto<
tuple_size_v<std::remove_reference_t<Tuple>>
>();
return indexer(
[&](auto...Is)->decltype(auto) {
return std::forward<F>(f)(
std::get<Is>(std::forward<Tuple>(tup))...
);
}
);
}
}
relatively easily and get the cleaner c++17 syntax ready to ship.
void delayed_dispatch() {
notstd::apply( func, params );
}
just replace notstd with std when your compiler upgrades and bob is your uncle.
Thinking about the problem some more based on the answer given I've found another way of solving the same problem:
template <int N, int M, typename D>
struct call_or_recurse;
template <typename ...Types>
struct dispatcher {
template <typename F, typename ...Args>
static void impl(F f, const std::tuple<Types...>& params, Args... args) {
call_or_recurse<sizeof...(Args), sizeof...(Types), dispatcher<Types...> >::call(f, params, args...);
}
};
template <int N, int M, typename D>
struct call_or_recurse {
// recurse again
template <typename F, typename T, typename ...Args>
static void call(F f, const T& t, Args... args) {
D::template impl(f, t, std::get<M-(N+1)>(t), args...);
}
};
template <int N, typename D>
struct call_or_recurse<N,N,D> {
// do the call
template <typename F, typename T, typename ...Args>
static void call(F f, const T&, Args... args) {
f(args...);
}
};
Which requires changing the implementation of delayed_dispatch() to:
void delayed_dispatch() {
dispatcher<Args...>::impl(func, params);
}
This works by recursively converting the std::tuple into a parameter pack in its own right. call_or_recurse is needed as a specialization to terminate the recursion with the real call, which just unpacks the completed parameter pack.
I'm not sure this is in anyway a "better" solution, but it's another way of thinking about and solving it.
As another alternative solution you can use enable_if, to form something arguably simpler than my previous solution:
#include <iostream>
#include <functional>
#include <tuple>
void f(int a, double b, void* c) {
std::cout << a << ":" << b << ":" << c << std::endl;
}
template <typename ...Args>
struct save_it_for_later {
std::tuple<Args...> params;
void (*func)(Args...);
template <typename ...Actual>
typename std::enable_if<sizeof...(Actual) != sizeof...(Args)>::type
delayed_dispatch(Actual&& ...a) {
delayed_dispatch(std::forward<Actual>(a)..., std::get<sizeof...(Actual)>(params));
}
void delayed_dispatch(Args ...args) {
func(args...);
}
};
int main() {
int a=666;
double b = -1.234;
void *c = NULL;
save_it_for_later<int,double,void*> saved = {
std::tuple<int,double,void*>(a,b,c), f};
saved.delayed_dispatch();
}
The first overload just takes one more argument from the tuple and puts it into a parameter pack. The second overload takes a matching parameter pack and then makes the real call, with the first overload being disabled in the one and only case where the second would be viable.
My variation of the solution from Johannes using the C++14 std::index_sequence (and function return type as template parameter RetT):
template <typename RetT, typename ...Args>
struct save_it_for_later
{
RetT (*func)(Args...);
std::tuple<Args...> params;
save_it_for_later(RetT (*f)(Args...), std::tuple<Args...> par) : func { f }, params { par } {}
RetT delayed_dispatch()
{
return callFunc(std::index_sequence_for<Args...>{});
}
template<std::size_t... Is>
RetT callFunc(std::index_sequence<Is...>)
{
return func(std::get<Is>(params) ...);
}
};
double foo(int x, float y, double z)
{
return x + y + z;
}
int testTuple(void)
{
std::tuple<int, float, double> t = std::make_tuple(1, 1.2, 5);
save_it_for_later<double, int, float, double> saved (&foo, t);
cout << saved.delayed_dispatch() << endl;
return 0;
}
a lot of answers have been provided but I found them too complicated and not very natural. I did it another way, without using sizeof or counters.
I used my own simple structure (ParameterPack) for parameters to access the tail of parameters instead of a tuple. Then, I appended all the parameters from my structure into function parameters, and finnally, when no more parameters were to be unpacked, I run the function.
Here is the code in C++11, I agree that there is more code than in others answers, but I found it more understandable.
template <class ...Args>
struct PackParameters;
template <>
struct PackParameters <>
{
PackParameters() = default;
};
template <class T, class ...Args>
struct PackParameters <T, Args...>
{
PackParameters ( T firstElem, Args... args ) : value ( firstElem ),
rest ( args... ) {}
T value;
PackParameters<Args...> rest;
};
template <class ...Args>
struct RunFunction;
template <class T, class ...Args>
struct RunFunction<T, Args...>
{
template <class Function>
static void Run ( Function f, const PackParameters<T, Args...>& args );
template <class Function, class... AccumulatedArgs>
static void RunChild (
Function f,
const PackParameters<T, Args...>& remainingParams,
AccumulatedArgs... args
);
};
template <class T, class ...Args>
template <class Function>
void RunFunction<T, Args...>::Run (
Function f,
const PackParameters<T, Args...>& remainingParams
)
{
RunFunction<Args...>::template RunChild ( f, remainingParams.rest,
remainingParams.value );
}
template <class T, class ...Args>
template<class Function, class ...AccumulatedArgs>
void RunFunction<T, Args...>::RunChild ( Function f,
const PackParameters<T, Args...>& remainingParams,
AccumulatedArgs... args )
{
RunFunction<Args...>:: template RunChild ( f, remainingParams.rest,
args..., remainingParams.value );
}
template <>
struct RunFunction<>
{
template <class Function, class... AccumulatedArgs>
static void RunChild ( Function f, PackParameters<>, AccumulatedArgs... args )
{
f ( args... );
}
template <class Function>
static void Run ( Function f, PackParameters<> )
{
f ();
}
};
struct Toto
{
std::string k = "I am toto";
};
void f ( int i, Toto t, float b, std::string introMessage )
{
float res = i * b;
std::cerr << introMessage << " " << res << std::endl;
std::cerr << "Toto " << t.k << std::endl;
}
int main(){
Toto t;
PackParameters<int, Toto, float, std::string> pack ( 3, t, 4.0, " 3 * 4 =" );
RunFunction<int, Toto, float, std::string>::Run ( f, pack );
return 0;
}