Does perfect forwarding in C++0x make reference_wrapper deprecated? - c++

As usual, code first:
#include <functional>
using namespace std;
using namespace std::tr1;
void f(int& r) { r++; }
template<class F, class P> void g1(F f, P t) { f(t); }
template<class F, class P> void g2(F f, P&& t) { f(forward<P>(t)); }
int main()
{
int i = 0;
g1(f, ref(i)); // old way, ugly way
g2(f, i); // new way, elegant way
}
In C++ 98, we don't have a nice way to pefect forward parameters through template functions. So the C++ gurus invented ref and cref to achieve that aim.
Now that we have had r-value reference and perfect forwarding, does it mean that ref and cref and the like should be deprecated?

Reference wrappers are still useful. This is the case when it's about storing things. For example, with reference wrappers you can make std::make_tuple and std::thread create objects which refer to some argument instead of copying them:
class abstract_job
{
public:
virtual ~abstract_job() {}
virtual void run() = 0;
};
class thread
{
public:
template<class Fun, class... Args>
thread(Fun&& f, Args&&... args)
{
typedef typename decay<Fun>::type fun_type;
typedef decltype( make_tuple(forward<Args>(args)...) ) tuple_type;
unique_ptr<abstract_job> ptr (new my_job<fun_type,tuple_type>(
forward<Fun>(fun),
make_tuple(forward<Args>(args)...)
));
// somehow pass pointer 'ptr' to the new thread
// which is supposed to invoke ptr->run();
}
...
};
...
void foo(const int&);
int main()
{
thread t (foo, 42); // 42 is copied and foo is invoked
t.join() // with a reference to this copy
int i = 23;
thread z (foo, std::cref(i)); // foo will get a reference to i
z.join();
}
Keep in mind that
make_tuple(std::ref(i)) // yields a tuple<int&>
make_tuple( i ) // yields a tuple<int>
Cheers!
s

That's assuming reference_wrapper was intended for that. Rather it seems to be mostly about allowing passing function objects by reference where they would be normally taken by value. - If you were to take arguments as T&& instead, wouldn't that mean that passing things by value becomes impossible?
#include <iostream>
#include <functional>
#include <algorithm>
class X: public std::unary_function<int, void>
{
int n;
public:
X(): n(0) {}
void operator()(int m) {n += m;}
int get_n() const { return n; }
};
template <class Iter, class Fun>
void for_each(Iter from, Iter to, Fun&& fun)
{
for (; from != to; ++from)
fun(*from);
}
int main()
{
int a[] = {1, 2, 3};
X x1;
::for_each(a, a + 3, x1);
std::cout << x1.get_n() << '\n'; //6
X x2;
std::for_each(a, a + 3, x2);
std::cout << x2.get_n() << '\n'; //0
X x3;
std::for_each(a, a + 3, std::ref(x3));
std::cout << x3.get_n() << '\n'; //6
}

Related

Recreate function signature and call via template packs in C++

I have C code that I want to rewrite in C++. The C code is part of a interpreter where the functions are defined in C however the actual call is from the interpreted source. Basically what it does is listed below:
#include <vector>
void f1(int a0) { }
void f2(int a0,int a1) { }
void f3(int a0,int a1,int a2) { }
void f4(int a0,int a1,int a2,int a3) { }
struct m {
void *p;
int c;
};
std::vector<m> ma;
int addfunc(void *p, int c) {
int i = ma.size();
ma.push_back({p,c});
return i;
}
void call(int idx, int *stack) {
switch (ma[idx].c) {
case 1:
((void (*)(int))ma[idx].p) (stack[0]);
break;
case 2:
((void (*)(int,int))ma[idx].p) (stack[0],stack[1]);
break;
case 3:
((void (*)(int,int,int))ma[idx].p) (stack[0],stack[1],stack[2]);
break;
case 4:
((void (*)(int,int,int,int))ma[idx].p) (stack[0],stack[1],stack[2],stack[3]);
break;
}
}
int main (void) {
int stack[5] = { 0,1,2,3,4 };
/* define */
int i1 = addfunc((void*)f1, 1);
int i2 = addfunc((void*)f2, 2);
int i3 = addfunc((void*)f3, 3);
int i4 = addfunc((void*)f4, 4);
/* call */
call(i1,stack);
call(i2,stack);
call(i3,stack);
call(i4,stack);
}
The addfunc creates a callable object specified by a function pointer and a signature, because the arguments are of the same type int only a count argument for the number of arguments is needed.
When I call a function I specify the function object's index and a stack. The actual c-call is decoded via the argument count and typecasted, the call arguments are taken from the stack.
How can I rewrite the addfunc and call functions as templates objects in C++? How can I use template packs to count the number of arguments for the given function and regenerate the call to the function?
How can I get rid of the switch statement and the function pointer typecast? I have seen that luawrapper's Binder class does something similar. However the code is quite complicated. In my case the arguments are all of the same type.
In the end I want to do something like (pseudocode):
vector<meth> ma;
...
int i0 = addfunc([](int a) { });
int i1 = addfunc([](int a,int b) { });
int i2 = addfunc([](int a,int b,int b) { });
int i3 = addfunc([](int a,int b,int c,int c) { });
...
ma[i0](stack);
ma[i1](stack);
ma[i2](stack);
ma[i3](stack);
Well, if they're just C functions, why not overload on the function pointer type?
std::function<void(std::array<int, 5>)> addfunc(void (*f)(int)) {
return [f](std::array<int, 5> const& a) { f(a[0]); };
}
std::function<void(std::array<int, 5>)> addfunc(void (*f)(int,int)) {
return [f](std::array<int, 5> const& a) { f(a[0], a[1]); };
}
// repeat for all necessary arities
Then create std::vector<std::function<void(std::array<int, 5>)>> and push back all your functions. It's easy, doesn't require any templates and will work reasonably well. It introduces the overhead of std::function, though.
You could get rid of that by introducing your own callable type (n of them), that would correspond to the overloads above, provide an operator() and store appropriate function type inside.
Live example.
Unfortunately, you won't be able to make a completely generic solution, as there is no way to type-erase arity.
One way you can simplify things would be to create a set of wrappers for your functions, each wrapper accepting a stack*, and calling implementation functions with arguments from said stack.
Than you do not need typecasts at all and a simple function pointer (to approriate wrapper) would do (no even need to type-erase).
I propose a C++17 solution (simplified following a Jarod42's observation: thanks) that I suppose is over-complicated.
But I find it funny...
First: a struct that, given (as template parameters) a type and a unsigned number, define a type as the type received.
template <typename T, std::size_t>
struct getType
{ using type = T; };
It's used to convert a variadic template list of numbers in a sequence of types (ints, in the following example) of the same length.
Next: a template type that register (setFunc()) and exec (callFunc()) a function returning void and a sequence of ints length as the first template parameter.
template <std::size_t N, typename = std::make_index_sequence<N>>
struct frHelper;
template <std::size_t N, std::size_t ... Is>
struct frHelper<N, std::index_sequence<Is...>>
{
using fnPnt_t = void(*)(typename getType<int, Is>::type...);
fnPnt_t fp = nullptr;
void setFunc (fnPnt_t fp0)
{ fp = fp0; }
void callFunc (std::array<int, sizeof...(Is)> const & a)
{ if ( fp ) fp(a[Is]...); }
};
Last: a template struct that inherit from a variadic list of preceding structs and enable (using) the setFunc() and the callFunc() members.
template <std::size_t N, typename = std::make_index_sequence<N>>
struct funcRegister;
template <std::size_t N, std::size_t ... Is>
struct funcRegister<N, std::index_sequence<Is...>>
: public frHelper<Is>...
{
using frHelper<Is>::setFunc...;
using frHelper<Is>::callFunc...;
};
Use.
First you have to declare an object of type funcRegister<N> where N is the max number of integer received from your functions plus one. So if you want to use f4(), so four integers, you have to declare
funcRegister<5u> fr;
Then you have to register the functions
fr.setFunc(f1);
fr.setFunc(f2);
fr.setFunc(f3);
fr.setFunc(f4);
and, given some std::array<int, N> of the right size, you can call the registered functions
std::array a1 { 1 };
std::array a2 { 1, 2 };
std::array a3 { 1, 2, 3 };
std::array a4 { 1, 2, 3, 4 };
fr.callFunc(a1); // call f1
fr.callFunc(a2); // call f2
fr.callFunc(a3); // call f3
fr.callFunc(a4); // call f4
The following is a full compiling C++17 example
#include <array>
#include <utility>
#include <iostream>
#include <type_traits>
template <typename T, std::size_t>
struct getType
{ using type = T; };
template <std::size_t N, typename = std::make_index_sequence<N>>
struct frHelper;
template <std::size_t N, std::size_t ... Is>
struct frHelper<N, std::index_sequence<Is...>>
{
using fnPnt_t = void(*)(typename getType<int, Is>::type...);
fnPnt_t fp = nullptr;
void setFunc (fnPnt_t fp0)
{ fp = fp0; }
void callFunc (std::array<int, sizeof...(Is)> const & a)
{ if ( fp ) fp(a[Is]...); }
};
template <std::size_t N, typename = std::make_index_sequence<N>>
struct funcRegister;
template <std::size_t N, std::size_t ... Is>
struct funcRegister<N, std::index_sequence<Is...>>
: public frHelper<Is>...
{
using frHelper<Is>::setFunc...;
using frHelper<Is>::callFunc...;
};
void f1(int) { std::cout << "f1 called" << std::endl; }
void f2(int,int) { std::cout << "f2 called" << std::endl;}
void f3(int,int,int) { std::cout << "f3 called" << std::endl;}
void f4(int,int,int,int) { std::cout << "f4 called" << std::endl;}
int main()
{
funcRegister<5u> fr;
fr.setFunc(f1);
fr.setFunc(f2);
fr.setFunc(f3);
fr.setFunc(f4);
std::array a1 { 1 };
std::array a2 { 1, 2 };
std::array a3 { 1, 2, 3 };
std::array a4 { 1, 2, 3, 4 };
fr.callFunc(a1);
fr.callFunc(a2);
fr.callFunc(a3);
fr.callFunc(a4);
}
Here is luawrapper's code extracted to be applied the above case. This is more for completion as for #Jerod42's code is preferable.
#include <iostream>
#include <string>
#include <array>
#include <vector>
#include <functional>
#include <vector>
template<typename T> struct tag {};
template<typename TFunctionObject, typename TFirstParamType>
struct Binder {
TFunctionObject function;
TFirstParamType param;
template<typename... TParams>
auto operator()(TParams&&... params)
-> decltype(function(param, std::forward<TParams>(params)...))
{
return function(param, std::forward<TParams>(params)...);
}
};
template<typename TCallback>
static void readIntoFunction(int *stack, TCallback&& callback)
{
callback();
}
template<typename TCallback, typename TFirstType, typename... TTypes>
static void readIntoFunction(int *stack, TCallback&& callback, tag<TFirstType>, tag<TTypes>... othersTags)
{
Binder<TCallback, const TFirstType&> binder{ callback, *stack };
return readIntoFunction(++stack, binder, othersTags...);
}
/* decompose arguments */
template<typename TFunctionType, typename... TOtherParams>
std::function<void(int*)> _addfunc(TFunctionType f, tag<void (*)(TOtherParams...)>) {
return std::function<void(int*)>([f](int *stack) {
readIntoFunction(stack, f, tag<TOtherParams>{}...);
});
}
template<typename TFunctionType>
std::function<void(int*)> addfunc(TFunctionType fn)
{
typedef typename std::decay<TFunctionType>::type RealFuncSig;
return _addfunc(std::move(fn), tag<RealFuncSig>{} );
}
void f1(int a0) { std::cout << a0 << std::endl; }
void f2(int a0, int a1) { std::cout << a0 << a1 << std::endl; }
int main() {
int stack[5] = { 0,1,2,3,4 };
auto a0 = addfunc(&f1);
auto a1 = addfunc(&f2);
a0(stack);
a1(stack);
}
you can use std:function as the parameter of the addfun() and also std::bind

How to create functor that wraps lambda with captured variable?

How has the functor below to be altered to work as a lambda wrapper?
template<typename T>
class F {
T f;
public:
F(T t){
f = t;
}
T& operator()(){
return f;
}
};
int main()
{
int x = 5;
F<int (*)(int, int)> f( [x](int a, int b){return a+b;} );
return 0;
}
The compiler says
error: no matching function for call to 'F<int (*)(int, int)>::F(main()::<lambda(int, int)>)'
F<int (*)(int, int)> f( [x](int a, int b){return a+b;} );
It's more complicated... Internally lambda functions that capture variables are not functions as such, are data structures. I not found any solution developed and many requests and questions unresolved, then I developed this minimal code to wrap lambda pointer not using std::function or any other standard function or dependence. Pure c++11.
Accepts all kinds of lambda captures, arguments by reference, return void, and supports top level functions and member methods.
// Type checkers
template<typename _Type>
struct IsVoid
{
static const bool value = false;
};
template<>
struct IsVoid<void>
{
static const bool value = true;
};
// Callable signature interfce
template<typename _ReturnType, typename..._ArgTypes>
struct Callable
{
typedef _ReturnType ReturnType;
typedef _ReturnType (*SignatureType)(_ArgTypes...);
virtual _ReturnType operator()(_ArgTypes...args) = 0;
};
// Function and lambda closure wrapper
template<typename _ClosureType, typename _ReturnType, typename..._ArgTypes>
struct Closure: public Callable<_ReturnType, _ArgTypes...>
{
typedef _ClosureType ClosureType;
const _ClosureType closureHandler;
Closure(const _ClosureType& handler)
: closureHandler(handler)
{
}
_ReturnType operator()(_ArgTypes...args) override
{
if(IsVoid<_ReturnType>::value)
closureHandler(args...);
else
return closureHandler(args...);
}
};
// Fuction template selector
template <typename _FunctionType>
class Function
: public Function<decltype(&_FunctionType::operator())>
{
};
// Function, lambda, functor...
template <typename _ReturnType, typename... _ArgTypes>
class Function<_ReturnType(*)(_ArgTypes...)>
{
public:
typedef Function<_ReturnType(*)(_ArgTypes...)> SelfType;
typedef _ReturnType(*SignatureType)(_ArgTypes...);
Callable<_ReturnType, _ArgTypes...>* callableClosure;
Function(_ReturnType(*function)(_ArgTypes...))
: callableClosure(new Closure<SignatureType, _ReturnType, _ArgTypes...>(function))
{
}
// Captured lambda specialization
template<typename _ClosureType>
Function(const _ClosureType& function)
: callableClosure(new Closure<decltype(function), _ReturnType, _ArgTypes...>(function))
{
}
_ReturnType operator()(_ArgTypes... args)
{
if(IsVoid<_ReturnType>::value)
(*callableClosure)(args...);
else
return (*callableClosure)(args...);
}
};
// Member method
template <typename _ClassType, typename _ReturnType, typename... _ArgTypes>
class Function<_ReturnType(_ClassType::*)(_ArgTypes...)>
{
public:
typedef Function<_ReturnType(_ClassType::*)(_ArgTypes...)> SelfType;
typedef _ReturnType(_ClassType::*SignatureType)(_ArgTypes...);
SignatureType methodSignature;
Function(_ReturnType(_ClassType::*method)(_ArgTypes...))
: methodSignature(method)
{
}
_ReturnType operator()(_ClassType* object, _ArgTypes... args)
{
if(IsVoid<_ReturnType>::value)
(object->*methodSignature)(args...);
else
return (object->*methodSignature)(args...);
}
};
// Const member method
template <typename _ClassType, typename _ReturnType, typename... _ArgTypes>
class Function<_ReturnType(_ClassType::*)(_ArgTypes...) const>
{
public:
typedef Function<_ReturnType(_ClassType::*)(_ArgTypes...) const> SelfType;
typedef _ReturnType(_ClassType::*SignatureType)(_ArgTypes...) const;
SignatureType methodSignature;
Function(_ReturnType(_ClassType::*method)(_ArgTypes...) const)
: methodSignature(method)
{
}
_ReturnType operator()(_ClassType* object, _ArgTypes... args)
{
if(IsVoid<_ReturnType>::value)
(object->*methodSignature)(args...);
else
return (object->*methodSignature)(args...);
}
};
Tests:
#include <iostream>
class Foo
{
public:
int bar(int a, int b)
{
return a + b;
}
};
int someFunction(int a, int b)
{
return a + b;
}
int main(int argc, char** argv)
{
int a = 10;
int b = 1;
// Lambda without capturing
Function<int(*)(int)> fn1([] (int b) -> int {
return b;
});
std::cout << fn1(2) << std::endl; // 2
// Lambda capturing variable
Function<int(*)(int)> fn2([a] (int c) -> int {
return a + c;
});
std::cout << fn2(-7) << std::endl; // 3
// Lambda capturing scope
Function<int(*)(int)> fn3([&] (int c) -> int {
return a + c;
});
std::cout << fn3(-5) << std::endl; // 5
// Arguments by reference
Function<void(*)(int&, int)> fn4([] (int& d, int f) {
d = d + f;
});
fn4(a, -3); // Void call
std::cout << a << std::endl; // 7
// Top level function reference
Function<int(*)(int, int)> fn6(someFunction);
std::cout << fn6(a, 4) << std::endl; // 11
// Member method
Foo* foo = new Foo();
Function<int(Foo::*)(int,int)> fn7(foo->bar);
std::cout << fn7(foo, a, 8) << std::endl; // 15
}
Works correctly wih gcc 4.9.
Thanks for your question.
A lambda can't directly be converted to a free function pointer if it captures something just because they are two different things.
A lambda with capturing values must save its state somewhere, but a function pointer is just a memory address thus it doesn't provide that functionality. So you would be allowed to do something
static_cast<int(*)(int,int)>([](int a, int b) { return a+b; })
but that's not your case.
Some solutions could be:
don't use a function pointer but use a std::function<int(int,int>) instead
provide a free function which invokes the lambda (not a good solution in your case, mostly meant to be used to inerface with legacy code I'd say
use a template function which provides the wrapping from lambda to function pointer by itself. Similar to the solution proposed here
Use simple workaround with decltype.
auto lambda = [x](int a, int b){return a+b;};
F<decltype(lambda)> f(lambda); // OK
To make it look concise, we can use macro:
#define DECLARE_F(OBJECT, LAMBDA) \
auto lambda = LAMBDA; \
F<decltype(lambda)> OBJECT(lambda)
Usage:
DECLARE_F(f, [x](int a, int b){return a+b;}); // 1 per line if used ## __LINE__

How to call a function several times in C++ with different parameters

I have the next code:
object a,b,c;
fun (a);
fun (b);
fun (c);
I wonder if it is there any way to do something similar in C++98 or C++11 to:
call_fun_with (fun, a, b, c);
Thanks
Here a variadic template solution.
#include <iostream>
template < typename f_>
void fun( f_&& f ) {}
template < typename f_, typename head_, typename... args_>
void fun( f_ f, head_&& head, args_&&... args) {
f( std::forward<head_>(head) );
fun( std::forward<f_>(f), std::forward<args_>(args)... );
}
void foo( int v ) {
std::cout << v << " ";
}
int main() {
int a{1}, b{2}, c{3};
fun(foo, a, b, c );
}
You may use the following using variadic template:
template <typename F, typename...Ts>
void fun(F f, Ts&&...args)
{
int dummy[] = {0, (f(std::forward<Ts>(args)), 0)...};
static_cast<void>(dummy); // remove warning for unused variable
}
or in C++17, with folding expression:
template <typename F, typename...Ts>
void fun(F&& f, Ts&&...args)
{
(static_cast<void>(f(std::forward<Ts>(args))), ...);
}
Now, test it:
void foo(int value) { std::cout << value << " "; }
int main(int argc, char *argv[])
{
fun(foo, 42, 53, 65);
return 0;
}
Using C++ 11, you can use std::function, this way (which is quite quick to write IMO)
void call_fun_with(std::function<void(int)> fun, std::vector<int>& args){
for(int& arg : args){
fun(arg);
}
}
or, a bit more generic:
template<typename FTYPE>
void call_fun_with(FTYPE fun, std::vector<int>& args){
for(int& arg : args){
fun(arg);
}
}
Live example
Live example, templated version
Note: std::function template arguments must be specified the following way: return_type(arg1_type, arg2_type,etc.)
EDIT: An alternative could be using std::for_each which actually does pretty much the same thing, but which I do not really like as to the semantics, which are more like "for everything in this container, do...". But that's just me and my (maybe silly) way of coding :)
A C++11 range-based (enhanced) for loop will recognise a braced-init-list as an initializer_list, which means something like the following will work:
for (auto &x : {a,b,c}) fun(x);
there are a lot of different way's...
#include <iostream>
#include <vector>
#include <algorithm>
void foo(int x) {
std::cout << x << "\n";
}
void call_fun_with(std::function<void(int)> fn, std::vector<int> lst) {
for(auto it : lst)
fn(it);
}
int main() {
std::vector<int> val = {1,2,3,4,5};
// c++98
std::for_each(val.begin(), val.end(), foo);
// c++11
// vector
call_fun_with(foo, val);
// c++11
// initializer_list
int a=0, b=1, c=2;
call_fun_with(foo, {a,b,c});
}
see here.

Passing member function with all arguments to std::function

How can I create a std::function from member function without need for typing std::placeholders::_1, std::placeholders::_2, etc - I would like to "placehold" all arguments, saving only the object itself.
struct Foo{
int bar(int,float,bool) {return 0;}
};
int baz(int,float,bool) {return 0;}
int main() {
Foo object;
std::function<int(int,float,bool)> fun1 = baz; // OK
std::function<int(int,float,bool)> fun2 = std::bind(&Foo::bar, object); // WRONG, needs placeholders
}
I don't want to provide arguments at this stage, I just want to store function + object somewhere. For example I would like to have std::vector with both global functions and member functions. It was easy to do with FastDelegate (fastdelegate::MakeDelegate(object, &Class::function)).
I don't want to use lambda as it would require me to retype arguments as well. I just want old FastDelegate behaviour.
You can use function template which will deduce all member function parameter types, like this:
template<typename Obj, typename Result, typename ...Args>
auto make_delegate(const Obj &x, Result (Obj::*fun)(Args...)) -> // ...
And will return special delegate object, which will contain your object (or pointer to it) and just forward all passed arguments to member function of underlying object:
template<typename Obj, typename Result, typename ...Args>
struct Delegate
{
Obj x;
Result (Obj::*f)(Args...);
template<typename ...Ts>
Result operator()(Ts&&... args)
{
return (x.*f)(forward<Ts>(args)...);
}
};
You will get following usage syntax:
function<int(int,float,bool)> fun = make_delegate(object, &Foo::bar);
Here is full example:
#include <functional>
#include <iostream>
#include <utility>
using namespace std;
struct Foo
{
int bar(int x, float y, bool z)
{
cout << "bar: " << x << " " << y << " " << z << endl;
return 0;
}
};
int baz(int x, float y, bool z)
{
cout << "baz: " << x << " " << y << " " << z << endl;
return 0;
}
template<typename Obj, typename Result, typename ...Args>
struct Delegate
{
Obj x;
Result (Obj::*f)(Args...);
template<typename ...Ts>
Result operator()(Ts&&... args)
{
return (x.*f)(forward<Ts>(args)...);
}
};
template<typename Obj, typename Result, typename ...Args>
auto make_delegate(const Obj &x, Result (Obj::*fun)(Args...))
-> Delegate<Obj, Result, Args...>
{
Delegate<Obj, Result, Args...> result{x, fun};
return result;
}
int main()
{
Foo object;
function<int(int,float,bool)> fun[] =
{
baz,
make_delegate(object, &Foo::bar) // <---- usage
};
for(auto &x : fun)
x(1, 1.0, 1);
}
Output is:
baz: 1 1 1
bar: 1 1 1
Live Demo on Coliru
If you don't want to use placeholders, then std::bind is not for you:
Use lambda:
Foo object;
std::function<int(int,float,bool)> fun = [&object](int a, float b, bool c) {
return object.bar(a,b,c);
};
You can capture object by value if you wish. Perhaps you realize this is no better than using placeholders, as you're typing parameters anyway — in fact you type more in this case!
You can easily do this with variadic generic lambdas in C++14:
template<typename F, typename C>
auto smart_bind(F f, C* c)
{
return [c, f](auto&&... args) { return (c->*f)(std::forward<decltype(args)>(args)...); };
}
// In your code:
std::function<int(int,float,bool)> fun2 = smart_bind(&Foo::bar, &object);
Live demo: https://ideone.com/deR4fy

C++ how to generalize class function parameter to handle many types of function pointers?

I do not know if what I am asking is doable, stupid or simple.
I've only recently started dwelling in template functions and classes, and I was wondering if the following scenario is possible:
A class which holds a function pointer to be called. The function pointer cannot be specific, but abstract, so that whenever the class's Constructor is called, it may accept different kinds of function pointers. When the class's execute function is called, it executes the function pointer allocated at construction, with an argument (or arguments).
Basically the abstraction is kept throughout the design, and left over the user on what function pointer and arguments to pass. The following code has not been tested, just to demonstrate what I'm trying to do:
void (*foo)(double);
void (*bar)(double,double);
void (*blah)(float);
class Instruction
{
protected:
double var_a;
double var_b;
void (*ptr2func)(double);
void (*ptr2func)(double,double);
public:
template <typename F> Instruction(F arg1, F arg2, F arg3)
{
Instruction::ptr2func = &arg1;
var_a = arg2;
var_b = arg3;
};
void execute()
{
(*ptr2func)(var_a);
};
};
I do not like the fact I have to keep a list inside the class of possible overloadable function pointers. How could I possibly improve the above to generalize it as much as possible so that it can work with any kind of function pointer thrown at it ?
Bear in mind, I will want to keep a container of those instantiated objects and execute each function pointer in sequence.
Thank you !
Edit: Maybe the class should be a template it'self in order to facilitate use with many different function pointers?
Edit2: I found a way around my problem just for future reference, don't know if it's the right one, but it works:
class Instruction
{
protected:
double arg1,arg2,arg3;
public:
virtual void execute() = 0;
};
template <class F> class MoveArm : public Instruction
{
private:
F (func);
public:
template <typename T>
MoveArm(const T& f,double a, double b)
{
arg1 = a;
arg2 = b;
func = &f;
};
void execute()
{
(func)(arg1,arg2);
};
};
However when importing functions, their function pointers need to be typedef'd:
void doIt(double a, double b)
{
std::cout << "moving arm at: " << a << " " << b << std::endl;
};
typedef void (*ptr2func)(double,double);
int main(int argc, char **argv) {
MoveArm<ptr2func> arm(doIt,0.5,2.3);
arm.execute();
return 0;
}
If you can use C++0x and variadic templates, you can achieve this by using combination of std::function, std::bind and perfect forwarding:
#include <iostream>
#include <functional>
template <typename Result = void>
class instruction
{
public:
template <typename Func, typename... Args>
instruction(Func func, Args&&... args)
{
m_func = std::bind(func, std::forward<Args>(args)...);
}
Result execute()
{
return m_func();
}
private:
std::function<Result ()> m_func;
};
double add(double a, double b)
{
return (a + b);
}
int main()
{
instruction<double> test(&add, 1.5, 2.0);
std::cout << "result: " << test.execute() << std::endl;
}
Example with output: http://ideone.com/9HYWo
In C++ 98/03, you'd unfortunately need to overload the constructor for up-to N-paramters yourself if you need to support variable-number of arguments. You'd also use boost::function and boost::bind instead of the std:: equivalents. And then there's also the issue of forwarding problem, so to do perfect forwarding you'd need to do an exponential amount of overloads depending on the amount of arguments you need to support. Boost has a preprocessor library that you can use to generate the required overloads without having to write all the overloads manually; but that is quite complex.
Here's an example of how to do it with C++98/03, assuming the functions you pass to the instruction won't need to take the arguments by modifiable reference, to do that, you also need to have overloads for P1& p1 instead of just const P1& p1.
#include <iostream>
#include <boost/function.hpp>
#include <boost/bind.hpp>
template <typename Result = void>
class instruction
{
public:
template <typename Func>
instruction(Func func)
{
m_func = func;
}
template <typename Func, typename P1>
instruction(Func func, const P1& p1)
{
m_func = boost::bind(func, p1);
}
template <typename Func, typename P1, typename P2>
instruction(Func func, const P1& p1, const P2& p2)
{
m_func = boost::bind(func, p1, p2);
}
template <typename Func, typename P1, typename P2, typename P3>
instruction(Func func, const P1& p1, const P2& p2, const P3& p3)
{
m_func = boost::bind(func, p1, p2, p3);
}
Result execute()
{
return m_func();
}
private:
boost::function<Result ()> m_func;
};
double add(double a, double b)
{
return (a + b);
}
int main()
{
instruction<double> test(&add, 1.5, 2.0);
std::cout << "result: " << test.execute() << std::endl;
}
Example: http://ideone.com/iyXp1
I also created a C++0x version with some example usage. You can probably better use the one given by reko_t but I nevertheless post this one. This one uses recursion to unpack a tuple with values, and thus a tuple to store the arguments to pass to the function. Note that this one does not use perfect forwarding. If you use this, you probably want to add this.
#include <iostream>
#include <string>
#include <tuple>
using namespace std;
template<unsigned N>
struct FunctionCaller
{
template<typename ... Typenames, typename ... Args>
static void call(void (*func)(Typenames ...), tuple<Typenames ...> tuple, Args ... args)
{
FunctionCaller<N-1>::call(func, tuple, get<N-1>(tuple), args ...);
}
};
template<>
struct FunctionCaller<0u>
{
template<typename ... Typenames, typename ... Args>
static void call(void (*func)(Typenames ...), tuple<Typenames ...> tuple, Args ... args)
{
func(args ...);
}
};
template<typename ... Typenames>
class Instruction
{
public:
typedef void (*FuncType)(Typenames ...);
protected:
std::tuple<Typenames ...> d_args;
FuncType d_function;
public:
Instruction(FuncType function, Typenames ... args):
d_args(args ...),
d_function(function)
{
}
void execute()
{
FunctionCaller<sizeof...(Typenames)>::call(d_function, d_args);
}
};
void test1()
{
cout << "Hello World" << endl;
}
void test2(int a, string b, double c)
{
cout << a << b << c << endl;
}
int main(int argc, char** argv)
{
Instruction<> i1(test1);
Instruction<int, string, double> i2(test2, 5, "/2 = ", 2.5);
i1.execute();
i2.execute();
return 0;
}
Well, what you are doing is correct. But since all pointers have the same size in C++ you can store one pointer (of void type):
void *funcptr;
and cast it to the necessary type when needed:
static_cast<(*void)(double,double)>(funcptr)(var_a, var_b);
But please, only use this when better techniques can not be used, but I can not tell if you don't tell us the bigger picture.
You might want to look at boost::function.