Suppose I have a versatile function with about four boolean flags:
int do_something(int arg, bool flag1, bool flag2, bool flag3, bool flag4) {
for(int i = 0; i < 1000000; i++) {
if(flag1)
// Do something 1
if(flag2)
// Do something 2
if(flag3)
// Do something 3
if(flag4)
// Do something 4
//Do something else 5
}
}
But I don't want to incur any costs for branching on these flags in the inner loop so I change them to templates (allowing the compiler to optimize away the conditionals):
template<bool flag1, bool flag2, bool flag3, bool flag4>
int do_something_helper(int arg) {
for(int i = 0; i < 1000000; i++) {
if(flag1)
// Do something 1
if(flag2)
// Do something 2
if(flag3)
// Do something 3
if(flag4)
// Do something 4
//Do something else 5
}
}
How can I write the do_something method now? The only way I know is as follows:
int do_something(int arg, bool flag1, bool flag2, bool flag3, bool flag4) {
if(flag1) {
if(flag2) {
if(flag3) {
if(flag4) {
return do_something_helper<true,true,true,true>(arg);
}else{
return do_something_helper<true,true,true,false>(arg);
}
}else{
if(flag4) {
return do_something_helper<true,true,false,true>(arg);
}else{
return do_something_helper<true,true,false,false>(arg);
}
}
//... You get the picture
}
Is there some way to get the compiler to write the above code automatically so I don't have to include this ugly monstrosity in my beautiful code-base?
What I would do is take a functor and a pack of arguments and an argument index and a range. Then I would replace the indexed argument with std::integral_constant<type, value> and call the functor. The bool case is easiest, as the range is obvious, so I would write that one first.
Then you can chain such replaces and functors to replace each one of the bools with compile time types. I would use the same functor for them all, with N overloads, esch replacing one bool with std::integral_constant<bool, X> where X is a template parameter.
The last one would then call the final method, with integral_constant instead of bool.
Note that this expands to an exponential amount of instantiations, so be careful.
The argument manipulation code would be fun to write.
Here is a live example.
Amusingly, the boilerplate to do the above is probably still bulkier, but hopefully less typo-prone and easier to test.
#include <iostream>
#include <tuple>
template<unsigned...Is> struct indexes {typedef indexes<Is...> type;};
template<unsigned min, unsigned max, unsigned...Is> struct make_indexes: make_indexes<min, max-1, max-1, Is...> {};
template<unsigned min, unsigned...Is> struct make_indexes<min, min, Is...>: indexes<Is...> {};
template<unsigned max, unsigned min=0>
using Indexes = typename make_indexes<min, max>::type;
template<unsigned index, typename Functor, typename... Args, unsigned... Before, unsigned... After>
void map_bool_to_compile_time_helper( indexes<Before...>, indexes<After...>, Functor&& f, std::tuple<Args...> args )
{
if (std::get<index>( args )) {
std::forward<Functor>(f)( std::get<Before>(args)..., std::true_type(), std::get<After>(args)... );
} else {
std::forward<Functor>(f)( std::get<Before>(args)..., std::false_type(), std::get<After>(args)... );
}
}
template<unsigned index, typename Functor, typename... Args>
void map_bool_to_compile_time( Functor&& f, Args&&... args )
{
map_bool_to_compile_time_helper<index>( Indexes<index>(), Indexes<sizeof...(Args), index+1>(), std::forward<Functor>(f), std::make_tuple<Args&&...>(std::forward<Args>(args)...) );
}
template<typename Functor, unsigned... indexes>
struct map_bools_to_compile_time_helper;
template<typename Functor, unsigned index, unsigned... indexes>
struct map_bools_to_compile_time_helper<Functor, index, indexes...> {
Functor&& f;
map_bools_to_compile_time_helper(Functor&& in):f(std::forward<Functor>(in)) {}
template< typename... Args>
void operator()( Args&&... args) const {
map_bool_to_compile_time<index>( map_bools_to_compile_time_helper<Functor, indexes...>{std::forward<Functor>(f)}, std::forward<Args>(args)... );
}
};
template<typename Functor>
struct map_bools_to_compile_time_helper<Functor> {
Functor&& f;
map_bools_to_compile_time_helper(Functor&& in):f(std::forward<Functor>(in)) {}
template<typename... Args>
void operator()( Args&&... args) const {
std::forward<Functor>(f)(std::forward<Args>(args)...);
}
};
template<unsigned... Is, typename Functor, typename... Args>
void map_bools_to_compile_time( indexes<Is...>, Functor&& f, Args&&... args ) {
map_bools_to_compile_time_helper<Functor, Is...>{ std::forward<Functor>(f) }( std::forward<Args>(args)... );
}
struct test {
template<bool b>
void operator()( int x, std::integral_constant< bool, b > ) { std::cout << x << ": " << b <<"!\n"; }
};
struct test2 {
template<bool b0, bool b1, bool b2>
void operator()( int x, std::integral_constant< bool, b0 >, std::integral_constant< bool, b1 >, std::integral_constant< bool, b2 > )
{
std::cout << x << ": " << b0 << b1 << b2 << "\n";
}
};
int main() {
map_bools_to_compile_time( indexes<1>(), test(), 1, true );
map_bool_to_compile_time<1>( test(), 2, false );
map_bools_to_compile_time( indexes<1,2,3>(), test2(), 3, true, false, true );
}
Updated with support for any number of arguments at any number of indexes.
You can use templates to organize static dispatch - which will allow to replace branching statement with function overload. This is a rather simple idea, here is a small example:
template <int Val>
struct Int2Type
{
static const int val_= Val;
};
int do_something(int arg, Int2Type<1>)
{
// do smth when flag == 1
}
int do_something(int arg, Int2Type<2>)
{
// do smth when flag == 2
}
... the same principle is applied (by the value of a flag needed overloaded function is called)
Related
I would like to let compiler deduce partially class template arguments from constructor.
The motivation is to write a protocol library where the existance (here the length in bits) of certain data depends of the value of last variable, so a conditional class must be used to model this.
The c++ code I want to implement should work like this, but I would like to implement it in a more expressive and simplified way, without having to set all the parameters in the template but leaving compiler deduce them:
Coliru link: https://coliru.stacked-crooked.com/a/bb15abb2a9c09bb1
#include <iostream>
template<typename T1, typename T2, typename F, int... Ints>
struct If : T1
{
const T2& condition;
constexpr If(const T2& cond) : condition(cond) {}
constexpr int bits() { return check() ? T1::bits : 0; }
constexpr bool check()
{
return (F{}(Ints, condition.value) || ...);
}
};
struct Variable1
{
int value{};
static constexpr int bits{ 5 };
};
struct Variable2
{
int value{};
static constexpr int bits{ 8 };
};
struct Datagram
{
Variable1 var1;
If<Variable2, Variable1, std::equal_to<int>, 1, 2> var2{ var1 };//It compiles and works OK under c++17. What I have...
//If<Variable2> var2{ var1, std::equal_to<int>{}, 1, 2 };// ...what I wish
};
int main()
{
Datagram data;
data.var1.value = 0;
std::cout << data.var2.bits() << "\n";//must be 0
data.var1.value = 1;
std::cout << data.var2.bits() << "\n";//must be 8
data.var1.value = 2;
std::cout << data.var2.bits() << "\n";//must be 8
}
Is this possible?
The concept you are probably looking for is "type erasure", e.g. via std::function. Something along these lines:
template<typename T1>
struct If : T1
{
std::function<bool()> checker_;
template <typename T2, typename F, typename... Args>
constexpr If(const T2& cond, F&& f, Args&&... args)
: checker_([=, &cond]() { return (f(args, cond.value) || ...); })
{}
constexpr int bits() { return check() ? T1::bits : 0; }
constexpr bool check()
{
return checker_();
}
};
Demo
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
}
The idea is to create the following functionality (Looks easy)
void test(int , float , char* ){ /*gets called*/ }
void main()
{
RegisterRPC( test , int , float , char* )
}
Pseudo-code to register the function:
std::map<std::string , std::function<void()> > functionarray;
template<typename F, typename... Args>
void RegisterRPC( F , Args )
{
// somehow add to functionarray
}
Then, when data comes from Network, the data needs to be decomposed to call test with the proper args.
ProcessData(data)
{
data.begin();
functionarray[data.get<char*>()] (
data.get<int>() ,
data.get<float>() ,
data.get<char*>() ); // the RegisterRPC parameters
}
I already found that Variadic Templates can store args
expanded parameter list for variadic template
And it can decopose args into classes
How can I iterate over a packed variadic template argument list?
So I believe its possible - just I dont get how..
Hope somebody can help.
Edit : In case somebody is interested in the complete solution :
#include <tuple>
#include <iostream>
#include <strstream>
#include <istream>
#include <sstream>
#include <string>
// ------------- 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...>
{};
// ----------UNPACK TUPLE AND APPLY TO FUNCTION ---------
using namespace std;
template<class Ret, class... Args, int... Indexes >
Ret apply_helper(Ret(*pf)(Args...), index_tuple< Indexes... >, tuple<Args...>&& tup)
{
return pf(forward<Args>(get<Indexes>(tup))...);
}
template<class Ret, class ... Args>
Ret apply(Ret(*pf)(Args...), const tuple<Args...>& tup)
{
return apply_helper(pf, typename make_indexes<Args...>::type(), tuple<Args...>(tup));
}
template<class Ret, class ... Args>
Ret apply(Ret(*pf)(Args...), tuple<Args...>&& tup)
{
return apply_helper(pf, typename make_indexes<Args...>::type(), forward<tuple<Args...>>(tup));
}
// --- make tuple ---
template <typename T> T read(std::istream& is)
{
T t; is >> t; cout << t << endl; return t;
}
template <typename... Args>
std::tuple<Args...> parse(std::istream& is)
{
return std::make_tuple(read<Args>(is)...);
}
template <typename... Args>
std::tuple<Args...> parse(const std::string& str)
{
std::istringstream ips(str);
return parse<Args...>(ips);
};
// ---- RPC stuff
class DataSource
{
std::string data;
public:
DataSource(std::string s) { data = s; };
template<class...Ts> std::tuple<Ts...> get() { return parse<Ts...>(data); };
};
std::map<std::string, std::function<void(DataSource*)> > functionarray;
template<typename... Args, class F>
void RegisterRPC(std::string name, F f) {
functionarray[name] = [f](DataSource* data){apply(f, data->get<Args...>()); };
}
// --------------------- TEST ------------------
void one(int i, double d, string s)
{
std::cout << "function one(" << i << ", " << d << ", " << s << ");\n";
}
int main()
{
RegisterRPC<int, double, string>("test1", one);
DataSource* data=new DataSource("5 2 huhu");
functionarray["test1"](data);
system("pause");
return 0;
}
// --------------------- TEST ------------------
First, write a "call with tuple". This takes a callable object f and a tuple t, and calls f( std::get<0>(t), std::get<1>(t), ... ).
here is one of many such implementations on stack overflow. You can write a better one in C++14, or wait for it to arrive in C++1z.
Second, write data.get<std::tuple<A,B,C,...>>() that returns a tuple of type A,B,C,.... This is easy:
template<class...Ts>
std::tuple<Ts...> DataSource::get() {
return std::tuple<Ts...>{get<Ts>()...}; // some compilers get order here wrong, test!
}
now our function array looks like this:
std::map<std::string , std::function<void(DataSource*)> > functionarray;
template<class...Args, class F>
std::function<void(DataSource*)> from_source( F f ) {
// `[f = std::move(f)]` is C++14. In C++11, just do `[f]` instead
return [f = std::move(f)](DataSource* data){
call_from_tuple( f, data->get<std::tuple<Args...>>() );
};
}
template<typename... Args, class F>
void RegisterRPC( F f ) {
functionarray.push_back( from_source<Args...>( std::move(f) ) );
}
and end use is:
void test(int , float , char* ){ /*gets called*/ }
void main()
{
RegisterRPC<int,float,char*>( test )
}
I recomment against using char*. I'd use std::string, or std::vector<char> or even std::unique_ptr<char[]>, so lifetime is extremely clear.
The trick is that we erase at the point where we know the type information, which is where we wrap the function. There, we give it instructions on how to get the types from the data source and call itself, leaving behind a function of type "data source -> nothing".
We take "Ts... -> nothing" (your F) and "(DataSource -> Ts)..." (the stream of data over the network) and compose it into "DataSource -> nothing" (the std::function you store).
For example, I have a tuple
std::tuple<int, int, int, int> a(2, 3, 1, 4);
and I want to get the position of its elements using such as the the following function.
int GetPosition(const std::tuple<int, int, int, int>& tp, int element);
Here 2's position is 0, 3's position is 1, 1's position is 3 and 4'position is 3. How to implement the function? A silly way is to
int GetPosition(const std::tuple<int, int, int, int>& tp, int element)
{
if (std::get<0>(tp) == element) return 0;
if (std::get<1>(tp) == element) return 1;
if (std::get<2>(tp) == element) return 2;
... // Write as more as an allowed max number of elements
}
Any better ways? Thanks.
UPDATE:
I eventually figured out a way to achieve this in a simpler way that also uses short-circuiting (and therefore performs less comparisons).
Given some machinery:
namespace detail
{
template<int I, int N, typename T, typename... Args>
struct find_index
{
static int call(std::tuple<Args...> const& t, T&& val)
{
return (std::get<I>(t) == val) ? I :
find_index<I + 1, N, T, Args...>::call(t, std::forward<T>(val));
}
};
template<int N, typename T, typename... Args>
struct find_index<N, N, T, Args...>
{
static int call(std::tuple<Args...> const& t, T&& val)
{
return (std::get<N>(t) == val) ? N : -1;
}
};
}
The function that clients are going to invoke eventually boils down to this simple trampoline:
template<typename T, typename... Args>
int find_index(std::tuple<Args...> const& t, T&& val)
{
return detail::find_index<sizeof...(Args), T, Args...>::
call(t, std::forward<T>(val));
}
Finally, this is how you would use it in your program:
#include <iostream>
int main()
{
std::tuple<int, int, int, int> a(2, 3, 1, 4);
std::cout << find_index(a, 1) << std::endl; // Prints 2
std::cout << find_index(a, 2) << std::endl; // Prints 0
std::cout << find_index(a, 5) << std::endl; // Prints -1 (not found)
}
And here is a live example.
EDIT:
If you want to perform the search backwards, you can replace the above machinery and the trampoline function with the following versions:
#include <tuple>
#include <algorithm>
namespace detail
{
template<int I, typename T, typename... Args>
struct find_index
{
static int call(std::tuple<Args...> const& t, T&& val)
{
return (std::get<I - 1>(t) == val) ? I - 1 :
find_index<I - 1, T, Args...>::call(t, std::forward<T>(val));
}
};
template<typename T, typename... Args>
struct find_index<0, T, Args...>
{
static int call(std::tuple<Args...> const& t, T&& val)
{
return (std::get<0>(t) == val) ? 0 : -1;
}
};
}
template<typename T, typename... Args>
int find_index(std::tuple<Args...> const& t, T&& val)
{
return detail::find_index<0, sizeof...(Args) - 1, T, Args...>::
call(t, std::forward<T>(val));
}
Here is a live example.
ORIGINAL ANSWER:
This does not really sound like a typical way one would use tuples, but if you really want to do this, then here is a way (works with tuples of any size).
First, some machinery (the well-known indices trick):
template <int... Is>
struct index_list { };
namespace detail
{
template <int MIN, int N, int... Is>
struct range_builder;
template <int MIN, int... Is>
struct range_builder<MIN, MIN, Is...>
{
typedef index_list<Is...> type;
};
template <int MIN, int N, int... Is>
struct range_builder : public range_builder<MIN, N - 1, N - 1, Is...>
{ };
}
template<int MIN, int MAX>
using index_range = typename detail::range_builder<MIN, MAX>::type;
Then, a couple of overloaded function templates:
#include <tuple>
#include <algorithm>
template<typename T, typename... Args, int... Is>
int find_index(std::tuple<Args...> const& t, T&& val, index_list<Is...>)
{
auto l = {(std::get<Is>(t) == val)...};
auto i = std::find(begin(l), end(l), true);
if (i == end(l)) { return -1; }
else { return i - begin(l); }
}
template<typename T, typename... Args>
int find_index(std::tuple<Args...> const& t, T&& val)
{
return find_index(t, std::forward<T>(val),
index_range<0, sizeof...(Args)>());
}
And here is how you would use it:
#include <iostream>
int main()
{
std::tuple<int, int, int, int> a(2, 3, 1, 4);
std::cout << find_index(a, 1) << std::endl; // Prints 2
std::cout << find_index(a, 2) << std::endl; // Prints 0
std::cout << find_index(a, 5) << std::endl; // Prints -1 (not found)
}
And here is a live example.
Slightly shorter than the accepted answer, and searching forwards not backwards (so it finds the first match, not the last match), and using constexpr:
#include <tuple>
template<std::size_t I, typename Tu>
using in_range = std::integral_constant<bool, (I < std::tuple_size<Tu>::value)>;
template<std::size_t I1, typename Tu, typename Tv>
constexpr int chk_index(const Tu& t, Tv v, std::false_type)
{
return -1;
}
template<std::size_t I1, typename Tu, typename Tv>
constexpr int chk_index(const Tu& t, Tv v, std::true_type)
{
return std::get<I1>(t) == v ? I1 : chk_index<I1+1>(t, v, in_range<I1+1, Tu>());
}
template<typename Tu, typename Tv>
constexpr int GetPosition(const Tu& t, Tv v)
{
return chk_index<0>(t, v, in_range<0, Tu>());
}
Modified based on comments. A simple way by modifying the canceled answer
template<class Tuple>
struct TupleHelper
{
TupleHelper(Tuple& _tp) : tp(_tp) {}
Tuple& tp;
template<int N>
int GetPosition(int element)
{
if (std::get<N>(tp) == element) return N;
return GetPosition<N+1>(element);
}
template<>
int GetPosition<std::tuple_size<Tuple>::value>(int element)
{
return -1;
}
};
use it as
TupleHelper<MyTupleTy>(myTuple).GetPosition<0>(element);
This seems work.
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¶ms, 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¶ms)
{ 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;
}