Storing boost::function object with variable number of arguments - c++

What I'm trying to achieve is creating a struct which stores any kind of method. I can later call struct_object.run() to run the method I've stored.
This method can return any kind of value and, most importantly, use any amount of parameters; however, I can't get around the "any amount of parameters" issue.
Mind you, the following code doesn't even build, mostly because I have no clue on what the correct syntax would be like.
ApplicationPair.h
template<typename T, typename... Args>
struct ApplicationPair
{
ApplicationPair(boost::function<T()> func, Args... arguments )
{
_func = func(Args::arguments...);
}
ApplicationPair() = delete;
void run();
boost::function<T(Args...)> _func;
};
#endif
And then, what I'd like to do is the following:
main.cpp
template<typename T, typename... Args>
void ApplicationPair<T,Args...>::run()
{
this->_func;
}
//TEST
int counter = 0;
void HelloWorld()
{
std::cout << "HelloWorld\n";
}
void printNumber(int i)
{
std::cout << "Print: " << i << std::endl;
}
void increaseCounter(int x)
{
counter+=x;
}
int main()
{
ApplicationPair<void> p1(HelloWorld);
ApplicationPair<void> p2(printNumber, 5);
ApplicationPair<void> p3(increaseCounter, 10);
p1.run();
p2.run();
p3.run();
return 0;
}
Basically, the methods I want to store shouldn't be modified or adapted in any way: I want to be able to create any kind of method without caring about the fact that struct ApplicationPair will store it for its own personal use.
All I get with this though is a long string of errors like:
error: in declaration ‘typename boost::enable_if_c<(! boost::is_integral::value), boost::function&>::type boost::function::operator=(Functor)’

In the below line:
ApplicationPair<void> p2(printNumber, 5);
you have to specify all types in template arguments list, not only void as return type, int as argument of constructor should also be added. Now args... is empty. What is wrong. The same with p3.
Make constructor as templated method taking paramters pack as argument for your callable:
template<class F, class ... Args>
ApplicationPair(F&& func, Args... arguments )
{
_func = boost::bind(std::forward<F>(func),arguments...);
}
then args... can be deduced when invoking constructor. Your class template takes only a type for return value.
template<class Ret>
struct ApplicationPair {
template<class F, class ... Args>
ApplicationPair(F&& func, Args... arguments )
{
_func = boost::bind(std::forward<F>(func),arguments...);
}
ApplicationPair() = delete;
void run() {
this->_func();
}
boost::function<Ret()> _func;
};
In constructor boost::bind is used to bind passed parameters to callable. You don't store parameters anywhere, therefore they must be bound in functor created by boost::bind.
Uses:
ApplicationPair<void> p1(HelloWorld);
ApplicationPair<void> p2(printNumber, 5);
ApplicationPair<void> p3(increaseCounter, 10);
Demo
Don't use boost::bind, it is limited to handle only max 9 arguments.

You've already gotten an answer but here's a C++17 alternative capable of deducing the return value type as well as the argument types of the function using a deduction guide, making both the return type and argument types part of the ApplicationPair<> type. I've chosen to store the arguments separately in a std::tuple<Args...>.
boost::function can be replaced with std::function in this example in case you later decide to go with the standard:
#include <boost/function.hpp>
#include <iostream>
#include <type_traits>
#include <tuple>
template<typename T, typename... Args>
struct ApplicationPair {
ApplicationPair() = delete;
ApplicationPair(Func func, Args... args) :
_func(func),
// store the arguments for later use
arguments(std::make_tuple(std::forward<Args>(args)...))
{}
decltype(auto) run() { // I'd rename this: decltype(auto) operator()()
return std::apply(_func, arguments);
}
boost::function<T(Args...)> _func;
std::tuple<Args...> arguments;
};
// deduction guide
template<typename Func, typename... Args>
ApplicationPair(Func, Args...) ->
ApplicationPair<std::invoke_result_t<Func, Args...>, Args...>;
int counter = 0;
void HelloWorld()
{
std::cout << "HelloWorld\n";
}
void printNumber(int i)
{
std::cout << "Print: " << i << std::endl;
}
int increaseCounter(int x) // changed return type for demo
{
counter+=x;
return counter;
}
int main()
{
// full deduction using the deduction guide
ApplicationPair p1(HelloWorld);
ApplicationPair p2(printNumber, 5);
ApplicationPair p3(increaseCounter, 10);
p1.run();
p2.run();
std::cout << p3.run() << '\n';
std::cout << p3.run() << '\n';
}

Related

c++ : variadic template and function overloading

see example below live : https://onlinegdb.com/Hkg6iQ3ZNI
#include <iostream>
#include <utility>
#include <type_traits>
class A
{
public:
A(int v=-10):v_(v){}
void print()
{
std::cout << "called A: " << v_ << std::endl;
}
private:
int v_;
};
void f(int v)
{
std::cout << "called f: " << v << std::endl;
}
template<typename T,typename ... Args>
void run(A&& a,
T&& t,
Args&& ... args)
{
a.print();
t(std::forward<Args>(args)...);
}
template<typename T,typename ... Args>
void run(T&& t,
Args&& ... args)
{
run(A(),
std::forward<T>(t),
std::forward<Args>(args)...);
}
int main()
{
int v_function=1;
int v_a = 2;
run(f,v_function);
return 0;
}
The code above compiles, runs and print (as expected):
called A: -10
called f: 1
but if the main function is modified to:
int main()
{
int v_function=1;
int v_a = 2;
run(f,v_function);
// !! added lines !!
A a(v_a);
run(a,f,v_function);
return 0;
}
then compilation fails with error:
main.cpp:30:6: error: no match for call to ‘(A) (void (&)(int), int&)’
t(std::forward(args)...);
~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
which seems to indicate that even when an instance of A is passed as first argument, the overload function
void(*)(T&&,Args&&...)
is called, and not
void(*)(A&&,T&&,Args&&...)
With
template<typename T,typename ... Args>
void run(A&& a,
T&& t,
Args&& ... args)
a is not a forwarding reference, but an rvalue reference. That means when you do run(a,f,v_function); that function will not be selected because a is an lvalue and those can't be bound to rvalue references. There are two quick ways to fix this. First, use std::move on a like
run(std::move(a),f,v_function);
but this isn't great. a isn't actually moved in the function so you are kind of violating the principle of least surprise.
The second option is to make A in the function a template type so it becomes a forwarding reference and then you can constrain it to be of type A like
template<typename A_, typename T,typename ... Args, std::enable_if_t<std::is_same_v<std::decay_t<A_>, A>, bool> = true>
void run(A_&& a,
T&& t,
Args&& ... args)
{
a.print();
t(std::forward<Args>(args)...);
}
Your code works, if you are calling run with an rvalue.
Playable example here.
As NathanOliver already sad: void run(A&& a, T&& t, Args&& ... args) expects an rvalue reference.
Basic idea of an rvalue reference: You are passing an rvalue to a function (e.g. a string literal). That value will be copied to the function. This work is unnecessary. Instead, you are just "moving" the reference to that value, so that it is "owned" by a different part of your program. Move constructors are a good starting point for understanding this problem.

How to use std::bind with the standard library and save the return type?

I'm working on a class that schedules functions by binding them in a queue like this:
std::queue <void()> q;
template<typename R,typename... ArgsT>
void
schedule(R& fn, ArgsT&... args)
{
q.push(std::bind(fn, std::forward<ArgsT>(args)...) );
};
template<typename R,typename... ArgsT>
void
schedule(R&& fn, ArgsT&&... args)
{
q.push(std::bind(fn, std::forward<ArgsT>(args)...) );
};
As you see I made the type in the queue void() to make it hold any type of function objects but now I can't get the return when I execute it. What should I do to solve this?
Note: I don't want to use an external library like boost and I don't know what kind of function the user will pass it.
Note: I don't want to use an external library like boost and I don't
know what's the kind of function the user will pass it.
What I usually do in this case is I use a base class (from Command pattern) in my queue, and then have two implementations, the one wrapping the bind, and the other (also wrapping the bind) exposing a function that allows getting the return value.
Here is an example of the returning specialization (at last):
#include <iostream>
#include <functional>
#include <memory>
struct ACmd
{
virtual void exec() = 0;
virtual ~ACmd(){}
};
template <class F>
struct Cmd;
template <class R, class ... Args>
struct Cmd<R(Args...)> : ACmd
{
R result_;
std::function<R()> func_;
template <class F>
Cmd(F&& func, Args&&... args): result_(), func_()
{
auto f = std::bind(std::forward<F>(func), std::forward<Args>(args)...);
func_ = [f](){
return f();
};
}
virtual void exec(){
result_ = func_();
}
const R& getResult() const {return result_;}
};
// Make function for convenience, could return by value or ptr -
// - your choice
template <class R, class F, class ...Args>
Cmd<R(Args...)>* cmd(F&& func, Args&&... args)
{
return new Cmd<R(Args...)>(func, std::forward<Args>(args)...);
}
//... And overload for void...
int foo(int arg) {
return arg;
}
int main() {
auto x = cmd<int>(foo, 10);
x->exec();
std::cout << x->getResult() << std::endl;
return 0;
}
The result of the execution of each element in the queue, it is void, you have already defined it as such. If the functions passed in are required to return a value, then you would need to limit the type(s) returned to a fixed type, use utilities such as std::any, std::variant or some covariant types (possible with a std::unique_ptr or std::shared_ptr).
The simplest is to fix the return type (at compile time);
template <typename R>
using MQ = std::queue<std::function<R()>>;
MQ<int> q;
See the sample below.
The queue declaration needs to be a queue of objects, such as std::function objects. The return value from a bind can be assigned to a function and then used as expected.
std::function is a polymorphic function wrapper, it implements type erasure patterns akin to any, but is specifically designed for functions and other callable objects.
By way of example;
template <typename R>
using MQ = std::queue<std::function<R()>>;
MQ<int> q;
template<typename R,typename... ArgsT>
void
schedule(R&& fn, ArgsT&&... args)
{
q.push(std::bind(std::forward<R>(fn), std::forward<ArgsT>(args)...) );
};
int main()
{
schedule([](int a) { std::cout << "function called" << std::endl; return a; }, 42);
std::cout << q.front()() << std::endl;
}

How to recover the type of a function pointer at runtime

In the code I register one or multiple function pointer in a manager class.
In this class I have a map that maps the argument types of the function to said function. It may look like so: std::map< std::vector<std::type_index> , void*>
template<typename Ret, typename... Args>
void Register(Ret(*function)(Args...)) {
void* v = (void*)function;
// recursively build type vector and add to the map
}
At runtime the code gets calls (from an external script) with an arbitrary number of arguments. These arguments can be read as primitive data types or as custom types that will be specified at compile time.
With every call from the script, I have to find out which function to call, and then call it. The former is easy and already solved (filling a vector with type_index in a loop), but I can't think of a solution for the latter.
My first approach was using variadic templates in recursion with an added template argument for each read type - but this turned out to be impossible since templates are constructed at compile time, and the arbitrary number of arguments is read at runtime.
Without variadic templates however, I don't see any possibility to achieve this. I considered boost::any instead of void*, but I didn't see how that would solve the need to cast back to the original type. I also thought of using std::function but that would be a templated type, so it could not be stored in a map for functions with different arguments.
(If it's unclear what I'm asking, think of LuaBinds possibility to register overloaded functions. I tried to understand how it's implemented there (without variadic templates, pre-C++11), but to no avail.)
Suppose you had the arguments in a vector of some kind, and a known function (fully).
You can call this. Call the function that does this invoke.
Next, work out how to do this for template<class... Args>. Augment invoke.
So you have written:
typedef std::vector<run_time_stuff> run_time_args;
template<class... Args>
void invoke( void(*func)(Args...), run_time_args rta )
at this point. Note that we know the types of the argument. I do not claim the above is easy to write, but I have faith you can figure it out.
Now we wrap things up:
template<class...Args>
std::function<void(run_time_args)> make_invoker(void(*func)(Args...)){
return [func](run_time_args rta){
invoke(func, rta);
};
}
and now instead of void* you store std::function<void(run_time_args)> -- invokers. When you add the function pointers to the mechanism you use make_invoker instead of casting to void*.
Basically, at the point where we have the type info, we store how to use it. Then where we want to use it, we use the stored code!
Writing invoke is another problem. It will probably involve the indexes trick.
Suppose we support two kinds of arguments -- double and int. The arguments at run time are then loaded into a std::vector< boost::variant<double, int> > as our run_time_args.
Next, let us extend the above invoke function to return an error in the case of parameter type mismatch.
enum class invoke_result {
everything_ok,
error_parameter_count_mismatch,
parameter_type_mismatch,
};
typedef boost::variant<int,double> c;
typedef std::vector<run_time_stuff> run_time_args;
template<class... Args>
invoke_result invoke( void(*func)(Args...), run_time_args rta );
now some boilerplate for the indexes trick:
template<unsigned...Is>struct indexes{typedef indexes type;};
template<unsigned Max,unsigned...Is>struct make_indexes:make_indexes<Max-1, Max-1,Is...>{};
template<unsigned...Is>struct make_indexes<0,Is...>:indexes<Is...>{};
template<unsigned Max>using make_indexes_t=typename make_indexes<Max>::type;
With that, we can write an invoker:
namespace helpers{
template<unsigned...Is, class... Args>
invoke_result invoke( indexes<Is...>, void(*func)(Args...), run_time_args rta ) {
typedef void* pvoid;
if (rta.size() < sizeof...(Is))
return invoke_result::error_parameter_count_mismatch;
pvoid check_array[] = { ((void*)boost::get<Args>( rta[Is] ))... };
for( pvoid p : check_array )
if (!p)
return invoke_result::error_parameter_type_mismatch;
func( (*boost::get<Args>(rts[Is]))... );
}
}
template<class... Args>
invoke_result invoke( void(*func)(Args...), run_time_args rta ) {
return helpers::invoke( make_indexes_t< sizeof...(Args) >{}, func, rta );
}
And that should work when func's args exactly match the ones passed in inside run_time_args.
Note that I was fast and loose with failing to std::move that std::vector around. And that the above doesn't support implicit type conversion. And I didn't compile any of the above code, so it is probably littered with typos.
I was messing around with variadic templates a few weeks ago and came up with a solution that might help you.
DELEGATE.H
template <typename ReturnType, typename ...Args>
class BaseDelegate
{
public:
BaseDelegate()
: m_delegate(nullptr)
{
}
virtual ReturnType Call(Args... args) = 0;
BaseDelegate* m_delegate;
};
template <typename ReturnType = void, typename ...Args>
class Delegate : public BaseDelegate<ReturnType, Args...>
{
public:
template <typename ClassType>
class Callee : public BaseDelegate
{
public:
typedef ReturnType (ClassType::*FncPtr)(Args...);
public:
Callee(ClassType* type, FncPtr function)
: m_type(type)
, m_function(function)
{
}
~Callee()
{
}
ReturnType Call(Args... args)
{
return (m_type->*m_function)(args...);
}
protected:
ClassType* m_type;
FncPtr m_function;
};
public:
template<typename T>
void RegisterCallback(T* type, ReturnType (T::*function)(Args...))
{
m_delegate = new Callee<T>(type, function);
}
ReturnType Call(Args... args)
{
return m_delegate->Call(args...);
}
};
MAIN.CPP
class Foo
{
public:
int Method(int iVal)
{
return iVal * 2;
}
};
int main(int argc, const char* args)
{
Foo foo;
typedef Delegate<int, int> MyDelegate;
MyDelegate m_delegate;
m_delegate.RegisterCallback(&foo, &Foo::Method);
int retVal = m_delegate.Call(10);
return 0;
}
Not sure if your requirements will allow this, but you could possibly just use std::function and std::bind.
The below solution makes the following assumptions:
You know the functions you want to call and their arguments
The functions can have any signature, and any number of arguments
You want to use type erasure to be able to store these functions and arguments, and call them all at a later point in time
Here is a working example:
#include <iostream>
#include <functional>
#include <list>
// list of all bound functions
std::list<std::function<void()>> funcs;
// add a function and its arguments to the list
template<typename Ret, typename... Args, typename... UArgs>
void Register(Ret(*Func)(Args...), UArgs... args)
{
funcs.push_back(std::bind(Func, args...));
}
// call all the bound functions
void CallAll()
{
for (auto& f : funcs)
f();
}
////////////////////////////
// some example functions
////////////////////////////
void foo(int i, double d)
{
std::cout << __func__ << "(" << i << ", " << d << ")" << std::endl;
}
void bar(int i, double d, char c, std::string s)
{
std::cout << __func__ << "(" << i << ", " << d << ", " << c << ", " << s << ")" << std::endl;
}
int main()
{
Register(&foo, 1, 2);
Register(&bar, 7, 3.14, 'c', "Hello world");
CallAll();
}

How do I determine the number of parameters of a std::function?

I have the following problem. Say you want to write a generic function that can take a lambda expression. I understand that if the parameter is of type std::function, then I could not only use lambdas, but also functions and even pointers to functions. So at a first step, I did the following:
void print(std::function<void(int, int)> fn) {
fn(1,2);
}
int main() {
print([](int i, int j) { std::cout << j <<','<<i<<'\n'; });
return 0;
}
Now the problem is that I want to make this function generic, meaning that I don't want the lambda expression to have only two parameters.
So I tried changing the signature of the print function to something more generic like:
template <class function_type>
void print(function_type fn);
But now the problem is that the function takes ANY object and I'm not ok with that.
But the main problem is that, I have no idea how many parameters the object fn can accept.
So in a way I'm looking for a compile time way to determine how many arguments fn has, and if possible to change the type of fn to std::function. And then, given that I know the number of parameters that fn accepts, is there a generic way to pack an arbitrary number of parameters to be passed to fn? I don't even know if this is possible within C++11. What I mean is that given the number of arguments, is there a way to pack parameters to pass to fn? So that if there are two arguments, then I would call
fn(arg1, arg2);
if there are three:
fn(arg1, arg2, arg3);
and so on.
Thank you all for your insight.
aa
The following snippets might be useful.
This gives the number of arguments that a std::function takes
template <typename Signature>
struct count_args;
template <typename Ret, typename... Args>
struct count_args<std::function<Ret(Args...)>> {
static constexpr size_t value = sizeof...(Args);
};
For example the following code compiles (clang 3.2, gcc 4.7.2 and icc 13.1.0)
static_assert(count_args<std::function<void() >>::value == 0, "Ops!");
static_assert(count_args<std::function<void(int) >>::value == 1, "Ops!");
static_assert(count_args<std::function<void(int, int)>>::value == 2, "Ops!");
As far as I understand, you want to call the function object passing the correct number of arguments, right? Then for each argument we need to provide a value which is convertible to its type. A solution with this generality is very hard (or even impossible). Hence, I'll present two alternatives.
1 Each argument is a value initialized object of its type. (This is what ecatmur suggested.)
template <typename Ret, typename... Args>
Ret call(const std::function<Ret(Args...)>& f) {
return f(Args{}...); // for the intel compiler replace {} with ()
}
2 A fixed value is given and all the arguments are implicitly initialized from this value:
template <typename Ret, typename... Args, typename Val, typename... Vals>
typename std::enable_if<sizeof...(Args) == sizeof...(Vals), Ret>::type
call(const std::function<Ret(Args...)>& f, const Val&, const Vals&... vals) {
return f(vals...);
}
template <typename Ret, typename... Args, typename Val, typename... Vals>
typename std::enable_if<(sizeof...(Args) > sizeof...(Vals)), Ret>::type
call(const std::function<Ret(Args...)>& f, const Val& val, const Vals&... vals) {
return call(f, val, val, vals...);
}
The three overloads are unambiguous and can be used as the following examples show:
{
std::function<char()> f = []() -> char {
std::cout << "f() ";
return 'A';
};
std::cout << call(f) << std::endl; // calls f()
std::cout << call(f, 0) << std::endl; // calls f()
}
{
std::function<char(int)> f = [](int i) -> char {
std::cout << "f(" << i << ") ";
return 'B';
};
std::cout << call(f) << std::endl; // calls f(0)
std::cout << call(f, 1) << std::endl; // calls f(1)
}
{
std::function<char(int, int)> f = [](int i, int j) -> char {
std::cout << "f(" << i << "," << j << ") ";
return 'C';
};
std::cout << call(f) << std::endl; // calls f(0, 0)
std::cout << call(f, 2) << std::endl; // calls f(2, 2)
}
Yes you can pack as many parameters to fn as you wish using variadic templates.
template <class function_type, class... Args>
void print(function_type fn, Args... args)
{
//Call fn with args
fn(std::forward<Args>(args...));
}
To find out how many args there are in the parameter pack, you can use sizeof...(args).
To determine the signature of a callable, you can use the solution from Inferring the call signature of a lambda or arbitrary callable for "make_function". You can then package the callable into a std::function, or create a tag and use parameter inference:
template<typename T> struct tag {};
template<typename F, typename... Args>
void print_impl(F &&fn, tag<void(Args...)>) {
fn(Args{}...);
}
template<typename F>
void print(F &&fn) {
print_impl(std::forward<F>(fn), tag<get_signature<F>>{});
}
Note this uses value-initialised arguments; if you want anything more complex you can build a std::tuple<Args...> and pass that along, invoking it per "unpacking" a tuple to call a matching function pointer.

How can I iterate over a packed variadic template argument list?

I'm trying to find a method to iterate over an a pack variadic template argument list.
Now as with all iterations, you need some sort of method of knowing how many arguments are in the packed list, and more importantly how to individually get data from a packed argument list.
The general idea is to iterate over the list, store all data of type int into a vector, store all data of type char* into a vector, and store all data of type float, into a vector. During this process there also needs to be a seperate vector that stores individual chars of what order the arguments went in. As an example, when you push_back(a_float), you're also doing a push_back('f') which is simply storing an individual char to know the order of the data. I could also use a std::string here and simply use +=. The vector was just used as an example.
Now the way the thing is designed is the function itself is constructed using a macro, despite the evil intentions, it's required, as this is an experiment. So it's literally impossible to use a recursive call, since the actual implementation that will house all this will be expanded at compile time; and you cannot recruse a macro.
Despite all possible attempts, I'm still stuck at figuring out how to actually do this. So instead I'm using a more convoluted method that involves constructing a type, and passing that type into the varadic template, expanding it inside a vector and then simply iterating that. However I do not want to have to call the function like:
foo(arg(1), arg(2.0f), arg("three");
So the real question is how can I do without such? To give you guys a better understanding of what the code is actually doing, I've pasted the optimistic approach that I'm currently using.
struct any {
void do_i(int e) { INT = e; }
void do_f(float e) { FLOAT = e; }
void do_s(char* e) { STRING = e; }
int INT;
float FLOAT;
char *STRING;
};
template<typename T> struct get { T operator()(const any& t) { return T(); } };
template<> struct get<int> { int operator()(const any& t) { return t.INT; } };
template<> struct get<float> { float operator()(const any& t) { return t.FLOAT; } };
template<> struct get<char*> { char* operator()(const any& t) { return t.STRING; } };
#define def(name) \
template<typename... T> \
auto name (T... argv) -> any { \
std::initializer_list<any> argin = { argv... }; \
std::vector<any> args = argin;
#define get(name,T) get<T>()(args[name])
#define end }
any arg(int a) { any arg; arg.INT = a; return arg; }
any arg(float f) { any arg; arg.FLOAT = f; return arg; }
any arg(char* s) { any arg; arg.STRING = s; return arg; }
I know this is nasty, however it's a pure experiment, and will not be used in production code. It's purely an idea. It could probably be done a better way. But an example of how you would use this system:
def(foo)
int data = get(0, int);
std::cout << data << std::endl;
end
looks a lot like python. it works too, but the only problem is how you call this function.
Heres a quick example:
foo(arg(1000));
I'm required to construct a new any type, which is highly aesthetic, but thats not to say those macros are not either. Aside the point, I just want to the option of doing:
foo(1000);
I know it can be done, I just need some sort of iteration method, or more importantly some std::get method for packed variadic template argument lists. Which I'm sure can be done.
Also to note, I'm well aware that this is not exactly type friendly, as I'm only supporting int,float,char* and thats okay with me. I'm not requiring anything else, and I'll add checks to use type_traits to validate that the arguments passed are indeed the correct ones to produce a compile time error if data is incorrect. This is purely not an issue. I also don't need support for anything other then these POD types.
It would be highly apprecaited if I could get some constructive help, opposed to arguments about my purely illogical and stupid use of macros and POD only types. I'm well aware of how fragile and broken the code is. This is merley an experiment, and I can later rectify issues with non-POD data, and make it more type-safe and useable.
Thanks for your undertstanding, and I'm looking forward to help.
If your inputs are all of the same type, see OMGtechy's great answer.
For mixed-types we can use fold expressions (introduced in c++17) with a callable (in this case, a lambda):
#include <iostream>
template <class ... Ts>
void Foo (Ts && ... inputs)
{
int i = 0;
([&]
{
// Do things in your "loop" lambda
++i;
std::cout << "input " << i << " = " << inputs << std::endl;
} (), ...);
}
int main ()
{
Foo(2, 3, 4u, (int64_t) 9, 'a', 2.3);
}
Live demo
(Thanks to glades for pointing out in the comments that I didn't need to explicitly pass inputs to the lambda. This made it a lot neater.)
If you need return/breaks in your loop, here are some workarounds:
Demo using try/throw. Note that throws can cause tremendous slow down of this function; so only use this option if speed isn't important, or the break/returns are genuinely exceptional.
Demo using variable/if switches.
These latter answers are honestly a code smell, but shows it's general-purpose.
If you want to wrap arguments to any, you can use the following setup. I also made the any class a bit more usable, although it isn't technically an any class.
#include <vector>
#include <iostream>
struct any {
enum type {Int, Float, String};
any(int e) { m_data.INT = e; m_type = Int;}
any(float e) { m_data.FLOAT = e; m_type = Float;}
any(char* e) { m_data.STRING = e; m_type = String;}
type get_type() const { return m_type; }
int get_int() const { return m_data.INT; }
float get_float() const { return m_data.FLOAT; }
char* get_string() const { return m_data.STRING; }
private:
type m_type;
union {
int INT;
float FLOAT;
char *STRING;
} m_data;
};
template <class ...Args>
void foo_imp(const Args&... args)
{
std::vector<any> vec = {args...};
for (unsigned i = 0; i < vec.size(); ++i) {
switch (vec[i].get_type()) {
case any::Int: std::cout << vec[i].get_int() << '\n'; break;
case any::Float: std::cout << vec[i].get_float() << '\n'; break;
case any::String: std::cout << vec[i].get_string() << '\n'; break;
}
}
}
template <class ...Args>
void foo(Args... args)
{
foo_imp(any(args)...); //pass each arg to any constructor, and call foo_imp with resulting any objects
}
int main()
{
char s[] = "Hello";
foo(1, 3.4f, s);
}
It is however possible to write functions to access the nth argument in a variadic template function and to apply a function to each argument, which might be a better way of doing whatever you want to achieve.
Range based for loops are wonderful:
#include <iostream>
#include <any>
template <typename... Things>
void printVariadic(Things... things) {
for(const auto p : {things...}) {
std::cout << p.type().name() << std::endl;
}
}
int main() {
printVariadic(std::any(42), std::any('?'), std::any("C++"));
}
For me, this produces the output:
i
c
PKc
Here's an example without std::any, which might be easier to understand for those not familiar with std::type_info:
#include <iostream>
template <typename... Things>
void printVariadic(Things... things) {
for(const auto p : {things...}) {
std::cout << p << std::endl;
}
}
int main() {
printVariadic(1, 2, 3);
}
As you might expect, this produces:
1
2
3
You can create a container of it by initializing it with your parameter pack between {}. As long as the type of params... is homogeneous or at least convertable to the element type of your container, it will work. (tested with g++ 4.6.1)
#include <array>
template <class... Params>
void f(Params... params) {
std::array<int, sizeof...(params)> list = {params...};
}
This is not how one would typically use Variadic templates, not at all.
Iterations over a variadic pack is not possible, as per the language rules, so you need to turn toward recursion.
class Stock
{
public:
bool isInt(size_t i) { return _indexes.at(i).first == Int; }
int getInt(size_t i) { assert(isInt(i)); return _ints.at(_indexes.at(i).second); }
// push (a)
template <typename... Args>
void push(int i, Args... args) {
_indexes.push_back(std::make_pair(Int, _ints.size()));
_ints.push_back(i);
this->push(args...);
}
// push (b)
template <typename... Args>
void push(float f, Args... args) {
_indexes.push_back(std::make_pair(Float, _floats.size()));
_floats.push_back(f);
this->push(args...);
}
private:
// push (c)
void push() {}
enum Type { Int, Float; };
typedef size_t Index;
std::vector<std::pair<Type,Index>> _indexes;
std::vector<int> _ints;
std::vector<float> _floats;
};
Example (in action), suppose we have Stock stock;:
stock.push(1, 3.2f, 4, 5, 4.2f); is resolved to (a) as the first argument is an int
this->push(args...) is expanded to this->push(3.2f, 4, 5, 4.2f);, which is resolved to (b) as the first argument is a float
this->push(args...) is expanded to this->push(4, 5, 4.2f);, which is resolved to (a) as the first argument is an int
this->push(args...) is expanded to this->push(5, 4.2f);, which is resolved to (a) as the first argument is an int
this->push(args...) is expanded to this->push(4.2f);, which is resolved to (b) as the first argument is a float
this->push(args...) is expanded to this->push();, which is resolved to (c) as there is no argument, thus ending the recursion
Thus:
Adding another type to handle is as simple as adding another overload, changing the first type (for example, std::string const&)
If a completely different type is passed (say Foo), then no overload can be selected, resulting in a compile-time error.
One caveat: Automatic conversion means a double would select overload (b) and a short would select overload (a). If this is not desired, then SFINAE need be introduced which makes the method slightly more complicated (well, their signatures at least), example:
template <typename T, typename... Args>
typename std::enable_if<is_int<T>::value>::type push(T i, Args... args);
Where is_int would be something like:
template <typename T> struct is_int { static bool constexpr value = false; };
template <> struct is_int<int> { static bool constexpr value = true; };
Another alternative, though, would be to consider a variant type. For example:
typedef boost::variant<int, float, std::string> Variant;
It exists already, with all utilities, it can be stored in a vector, copied, etc... and seems really much like what you need, even though it does not use Variadic Templates.
There is no specific feature for it right now but there are some workarounds you can use.
Using initialization list
One workaround uses the fact, that subexpressions of initialization lists are evaluated in order. int a[] = {get1(), get2()} will execute get1 before executing get2. Maybe fold expressions will come handy for similar techniques in the future. To call do() on every argument, you can do something like this:
template <class... Args>
void doSomething(Args... args) {
int x[] = {args.do()...};
}
However, this will only work when do() is returning an int. You can use the comma operator to support operations which do not return a proper value.
template <class... Args>
void doSomething(Args... args) {
int x[] = {(args.do(), 0)...};
}
To do more complex things, you can put them in another function:
template <class Arg>
void process(Arg arg, int &someOtherData) {
// You can do something with arg here.
}
template <class... Args>
void doSomething(Args... args) {
int someOtherData;
int x[] = {(process(args, someOtherData), 0)...};
}
Note that with generic lambdas (C++14), you can define a function to do this boilerplate for you.
template <class F, class... Args>
void do_for(F f, Args... args) {
int x[] = {(f(args), 0)...};
}
template <class... Args>
void doSomething(Args... args) {
do_for([&](auto arg) {
// You can do something with arg here.
}, args...);
}
Using recursion
Another possibility is to use recursion. Here is a small example that defines a similar function do_for as above.
template <class F, class First, class... Rest>
void do_for(F f, First first, Rest... rest) {
f(first);
do_for(f, rest...);
}
template <class F>
void do_for(F f) {
// Parameter pack is empty.
}
template <class... Args>
void doSomething(Args... args) {
do_for([&](auto arg) {
// You can do something with arg here.
}, args...);
}
You can't iterate, but you can recurse over the list. Check the printf() example on wikipedia: http://en.wikipedia.org/wiki/C++0x#Variadic_templates
You can use multiple variadic templates, this is a bit messy, but it works and is easy to understand.
You simply have a function with the variadic template like so:
template <typename ...ArgsType >
void function(ArgsType... Args){
helperFunction(Args...);
}
And a helper function like so:
void helperFunction() {}
template <typename T, typename ...ArgsType >
void helperFunction(T t, ArgsType... Args) {
//do what you want with t
function(Args...);
}
Now when you call "function" the "helperFunction" will be called and isolate the first passed parameter from the rest, this variable can b used to call another function (or something). Then "function" will be called again and again until there are no more variables left. Note you might have to declare helperClass before "function".
The final code will look like this:
void helperFunction();
template <typename T, typename ...ArgsType >
void helperFunction(T t, ArgsType... Args);
template <typename ...ArgsType >
void function(ArgsType... Args){
helperFunction(Args...);
}
void helperFunction() {}
template <typename T, typename ...ArgsType >
void helperFunction(T t, ArgsType... Args) {
//do what you want with t
function(Args...);
}
The code is not tested.
#include <iostream>
template <typename Fun>
void iteratePack(const Fun&) {}
template <typename Fun, typename Arg, typename ... Args>
void iteratePack(const Fun &fun, Arg &&arg, Args&& ... args)
{
fun(std::forward<Arg>(arg));
iteratePack(fun, std::forward<Args>(args)...);
}
template <typename ... Args>
void test(const Args& ... args)
{
iteratePack([&](auto &arg)
{
std::cout << arg << std::endl;
},
args...);
}
int main()
{
test(20, "hello", 40);
return 0;
}
Output:
20
hello
40