Common callbacks

Extensions

Related

So, I am trying to learn more about metaprogramming a template, and I believe this is a good exercise for him.

I am trying to write code that can call a function with any number of arguments that I like.

// First function to call
int add (int x, int y);

// Second function to call
double square (double x);

// Third func to call
void go ();

The callback creation code should look like this:

// Write a callback object that
// will be executed after 42ms for "add"
Callback <int, int, int> c1;
c1.func = add;
c1.args.push_back (2); // these are the 2 args
c1.args.push_back (5); // to pass to the "add" function
                         // when it is called

Callback <double, double> c2;
c2.func = square;
c2.args.push_back (52.2);

What I think is the use of metaprogramming templates. I want to be able to declare callbacks, for example to write such a structure (remember this is VERY PSEUDOcode)

<TEMPLATING ACTION << ANY NUMBER OF TYPES GO HERE >>>
struct callback
{
    double execTime; // when to execute
    TYPE1 (* func) (TYPE2 a, TYPE3 b);

    void * argList; // a stored list of arguments
                      // to plug in when it is time to call __func__
};

So, to call with

Callback <int, int, int> c1;

You will automatically create for yourself, HARDCORE TEMPERATURE ACTION> structure similar

struct callback
{
    double execTime; // when to execute
    int (* func) (int a, int b);

    void * argList; // this would still be void *,
                      // but I somehow need to remember
                      // the types of the args..
} ;

, ?

+5
4

variadic templates, . , , .

Variadic "...". ( ) , .

template <typename ... Args>
class Variadic {
public:
   operator()(Args&& ... args);
};

.

Variadic<Args>::operator(Args&& ... args) {
    func(args...);
}

std::forward; , . , :

template <typename ReturnValue, typename ... Args>
class Callback {
    typedef ReturnValue (*Func)(Args ... args);

    double execTime;
    Func func;
    Args... args;

public:
    Callback(double et, Func f) : execTime(et), func(f) {}
    ReturnValue operator()(Args&& ... a);
    ReturnValue operator()();
};

template <typename ReturnValue, typename ... Args>
ReturnValue Callback<ReturnValue, Args>::operator()(Args&& ... a) {
    return (*func)(std::forward(a)...);
}
template <typename ReturnValue, typename ... Args>
ReturnValue Callback<ReturnValue, Args>::operator()() {
    return operator(*func)(args...);
}
+2

boost:: bind. , ... , , , . , , .

+1

++ 0x , , . , . , 1 3 , :

class null_class {};

template <class func, class arg1, class arg2, class arg3>
class callback_t { 
    func f;
    arg1 a;
    arg2 b;
    arg3 c;
public:
    callback_t(func f, arg1 a, arg2 b, arg3 c) : f(f), a(a), b(b), c(c) {}
    double operator()() const { return f(a, b, c); }
};

template <class func, class arg1, class arg2> 
class callback_t<func, arg1, arg2, null_class> { 
    func f;
    arg1 a;
    arg2 b;
public:
    callback_t(func f, arg1 a, arg2 b) : f(f), a(a), b(b) {}
    double operator()() const { return f(a, b); }
};

template <class func, class arg1> 
class callback_t<func, arg1, null_class, null_class> {
    func f;
    arg1 a;
public:
    callback_t(func f, arg1 a) : f(f), a(a) {}
    double operator()() const { return f(a); }
};

template <class func, class arg1, class arg2, class arg3>
callback_t<func, arg1, arg2, arg3> 
callback(func f, arg1 a, arg2 b, arg3 c) { 
    return callback_t<func, arg1, arg2, arg3>(f, a, b, c);
}

template <class func, class arg1, class arg2>
callback_t<func, arg1, arg2, null_class> 
callback(func f, arg1 a, arg2 b) {
    return callback_t<func, arg1, arg2, null_class>(f, a, b);
}

template <class func, class arg>
callback_t<func, arg, null_class, null_class>
callback(func f, arg a) {
    return callback_t<func, arg, null_class, null_class>(f, a);
}

#ifdef TEST
#include <iostream>

double square(double d) { 
    return d * d;
}

double add(double a, double b) { 
    return a + b;
}

double sum(double a, double b, double c) { 
    return a + b + c;
}

int main() {
    double a = 2.0, b = 3.0, c=4.0;

    double d = callback(square, a)();
    double e = callback(add, b, c)();
    double f = callback(sum, a, b, c)();

    std::cout << "2.0 squared = " << d << "\n";
    std::cout << "3.0 + 4.0 = " << e << "\n";
    std::cout << "Sum = " << f << "\n";
    return 0;
}

#endif

, (, , ).

0

, Boost.Function, , , ;)

-, . , , ;)

Callback< int(int,int) > callback;

, , add: int add(int, int). , , .

, : ?

1.

, Boost.Fusion, ( , ).

, Boost.FunctionTypes, .

2.

// It is nice to have a base class
// Generally callbacks do not return anything though...
struct CallbackBase
{ 
  virtual ~CallbackBase();
  virtual void execute() const = 0;
};

namespace func_ = boost::function_types;

template <
  class Parameters,
  class N = typename mpl_::minus<
    typename mpl_::size< Parameters >::type,
    mpl_::size_t<1>
  >::type
>
class Streamer
{
public:
  typedef Streamer< Parameters, typename mpl_::minus<N,1>::type > next_type;
  typedef typename mpl_::size< Parameters >::type size_type;
  typedef typename mpl_::minus< size_type, N >::type index_type;
  typedef typename mpl_::at<Parameters, index_type>::type arg_type;

  Streamer(Parameters& p): mParameters(p) {}

  next_type operator<<(arg_type arg)
  {
    boost::fusion::at_c<index_type>(mParameters) = arg;
    return next_type(mParameters);
  }

private:
  Parameters& mParameters;
};

template <class Parameters>
struct Streamer<Paramaters,0>
{
  Streamer(Parameters&) {}
};


template <class Function>
class Callback: public CallbackBase
{
public:
  typedef typename func_::result_type<Function>::type result_type;
  typedef typename func_::parameters_type<Function>::type parameters_type;
  typedef typename func_::function_pointer<
    typename func_::components<Function>::type
  >::type function_pointer;

  Callback(function_pointer f): mFunction(f) {}

  virtual void execute() const
  {
    mReturn = Invoke<function_pointer>::Do(f,mParameters);
  }

  Streamer<parameters_type> operator<<(typename mpl_::at<parameters_type, 0>::type arg)
  {
    boost::fusion::at_c<0>(mParameters) = arg;
    return Streamer<parameters_type>(mParameters);
  }

private:
  function_pointer f;
  result_type mResult;
  parameters_type mParameters;
};

Good how far I went. I have not dealt with an actual call requiring unpacking a tuple to pass arguments to a function.

So far, the use would be:

int add(int,int);

void pass(const CallbackBase& b);

int main(int argc, char* argv[])
{
  Callback<int(int,int)> c(&add);
  c << 2 << 4;
  pass(c);
}

I highly recommend you go deeper into Boost.Fusion if you want to continue your studies in this domain, as metaprogramming as a clean template is often fruitless if you cannot bring the result to the world of runtime :)

0
source

All Articles