Skip to content

Instantly share code, notes, and snippets.

@eruffaldi
Last active August 29, 2015 14:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eruffaldi/815aaa0f9333abea3a70 to your computer and use it in GitHub Desktop.
Save eruffaldi/815aaa0f9333abea3a70 to your computer and use it in GitHub Desktop.
/**
* Binadable Class
*/
#include <functional>
#include <boost/any.hpp>
#include <vector>
#include <iostream>
#include <memory>
#include <type_traits>
#include <typeinfo>
#include <typeindex>
#include <cstddef>
template<std::size_t...> struct int_sequence {};
template<std::size_t N, std::size_t... Is> struct make_int_sequence
: make_int_sequence<N-1, N-1, Is...> {};
template<std::size_t... Is> struct make_int_sequence<0, Is...>
: int_sequence<Is...> {};
template <class X>
struct arity {};
template<class R, class... Args>
struct arity<R(Args...) >
{
enum { value = sizeof...(Args) };
};
template<class R, class... Args>
struct arity<std::function<R(Args...)> >
{
enum { value = sizeof...(Args) };
};
template<int> // begin with 0 here!
struct placeholder_template
{};
namespace std
{
template<int N>
struct is_placeholder< placeholder_template<N> >
: integral_constant<int, N+1> // the one is important
{};
}
template< class T>
struct getfunctioner {};
template< class R, class U, class...Args>
struct getfunctioner<R (U::*)(Args...) > {
typedef std::function<R(Args...)> target;
using fx = R(Args...);
};
template< class R, class...Args>
struct getfunctioner< std::function<R(Args...) > > {
typedef std::function<R(Args...)> target;
using fx = R(Args...);
};
template< class R, class...Args>
struct getfunctioner<R(Args...)> {
typedef std::function<R(Args...)> target;
using fx = R(Args...);
};
// utility
template<class R, class U, class... Args, std::size_t... Is>
auto bindthissub(R (U::*p)(Args...), U * pp, int_sequence<Is...>) -> decltype(std::bind(p, pp, placeholder_template<Is>{}...))
{
return std::bind(p, pp, placeholder_template<Is>{}...);
}
// binds a member function only for the this pointer using std::bind
template<class R, class U, class... Args>
auto bindthis(R (U::*p)(Args...), U * pp) -> decltype(bindthissub(p,pp,make_int_sequence< sizeof...(Args) >{}))
{
return bindthissub(p,pp,make_int_sequence< sizeof...(Args) >{});
}
template <class X>
struct call_n_args {};
// template class for managing the invokation
template <class R, class... Args>
struct call_n_args<std::function<R(Args...) > >
{
template <typename Container,std::size_t... IndicesFor>
static boost::any
call(std::function<R(Args...)> & f, Container& c, int_sequence<IndicesFor...> )
{
return f( boost::any_cast<Args>(c.at(IndicesFor))...);
}
};
// base class for dynamic invocation
class OperatorBase
{
public:
virtual boost::any call(std::vector<boost::any> & params) = 0;
virtual void* asfx() = 0;
virtual const std::type_info & assig() = 0;
template <class Sig>
std::function<Sig> & as()
{
if(typeid(Sig) != assig())
{
std::cout << typeid(Sig).name() << " vs expected " << assig().name() << std::endl;
throw std::exception();
}
else
return *(std::function<Sig> *)asfx();
}
};
// generic operator wrapper, templated over the std::function<Sig>
template <class T>
class Operator: public OperatorBase
{
public:
Operator(const T & x) : fx_(x) {}
typedef T value_t;
typedef typename getfunctioner<T>::fx Sig;
value_t fx_;
virtual const std::type_info &assig()
{
return typeid(Sig);
}
// all std::function are the same ...
virtual void *asfx()
{
return (void*)&fx_;
}
/// invokation given params and return value
virtual boost::any call(std::vector<boost::any> & params)
{
if(params.size() != arity<T>::value)
{
std::cout << "argument count mismatch\n";
throw std::exception();
}
return call_n_args<T>::call(fx_,params, make_int_sequence< arity<T>::value >{});
}
};
// base class to which operations can be added
class DynamicInvoke
{
public:
// Note: addOperation without biding this requires to pass the correct type pointer
template <class T, class Y>
void addOperation(const char * name, T a, Y b)
{
typedef typename getfunctioner<T>::target target_t;
target_t x = bindthis(a, b);
operators.push_back(std::shared_ptr<OperatorBase>(new Operator<target_t>(x)));
}
std::vector<std::shared_ptr<OperatorBase> > operators;
};
class Shape: public DynamicInvoke
{
public:
int draw(int a, const char * b)
{
std::cout << "invoked pippo " << a << " " << b << std::endl;
return 1;
}
Shape()
{
addOperation("draw",&Shape::draw,this);
}
};
class DummyClass
{
public:
int draw(int a, const char * b);
};
int main (int argc, char * argv[])
{
// wrap pippo inside class Pippo of class base
// allow for: introspection, call by variant
Shape p;
boost::any r;
std::vector<boost::any> w;
w.push_back(10);
w.push_back((const char*)"ciao");
(p.operators[0])->call(w);
using Sig = int(int,const char * a);
(p.operators[0])->as<Sig>()(10,"ciao");
(p.operators[0])->as< getfunctioner<decltype(&DummyClass::draw)>::fx >()(10,"ciao");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment