Adding a callback to a variadic template class - impossible? - c++

I'm trying to make a templated class, which has an Add method, that attaches a function callback to the class, so when I can then call it from there with the specified arguments list.It compiles fine, except for the part where I invoke the callback.It just doesn't accept the arguments, I've tried everything I can think of, but it still gives me the same "cannot expand parameter pack" error.Im using Visual Studio 2012 with the Microsoft Visual C++ Compiler Nov 2012 CTP (v120_CTP_Nov2012)
Here is the example source:
template
class Variadic
{
private:
void (*)($arguments...) callbackPtr;
public:
Variadic();
~Variadic();
void Attach(void (*callback)($arguments...));
void operator()($arguments... arguments);
};
I then add a callback to it:
template<typename... $arguments>
void Variadic<$arguments...>::Attach(void (*callback)($arguments...))
{
callbackPtr = callback;
}
And with the () operator I execute it:
template<typename... $arguments>
void Variadic<$arguments...>::operator()($arguments... arguments)
{
(callbackPtr)(arguments...);
}
In main.cpp I do a small test:
void test(int testInt, float testFloat)
{
//DoNothing
}
int main()
{
Variadic<int, float> var; //create one that will have a callback that takes an int and a float argument
var.Attach(test); //attach test, which takes an int and a float as arguments
var(2, 3.0f); //try to call it
}
The problem comes when I build - it gives me 2 errors at this exact line: (callbackPtr)(arguments...);
The errors are:
error C3546: '...' : there are no parameter packs available to expand
error C2065: 'arguments' : undeclared identifier
At first I thought it was a syntax problem and I wasn't passing arguments... properly, but I tried every way possible, it still gives me the same error.I can't find much info on "parameter pack expansion" in google either.What could I be doing wrong?I'm sure I'm somehow incorrectly using the (callbackPtr)(arguments...); call, but can't figure out how.
Any help would be appreciated.

Before I get into the answer, some things you should know:
The Microsoft VC++ November 2012 CTP does not play nice with Variadics and Function Pointers / Function Signatures. In almost all cases, it is necessary to expand them manually by hand. It sucks majorly, but you'll have to live with it until all that money we throw at VS and VC++ actually bears fruit and we get a compiler with a good chunk of C++11 features that other compilers are already supporting.
Passing function pointers and having the compiler determine the right type is a little trickier than most people would guess at first blush. There's a lot of type seducing deducting and template specialization that goes into it.
With that aside, it takes a lot of template magic and a lot of interesting functionality to have callbacks based on function pointers and member functions, rather than just using std::function<>. Before I show you the solution I ended up using, I seriously encourage you to use a std::vector<std::function<[RETURNTYPE]( [PARAMS] )> > (or just std::function for a single return) to save yourself the massive headache of trying to make this all work out. In either case, see my answer underneath #Insilico's for a Callback and Event system that works fine in GCC with variadic templates.
For a version that works in VC++, as I said before, you have to hack away at the various definitions manually, which I ended up creating a Callback Class and an Event class to do. It's for multiple callbacks, but you can simplify the Event class to be a single attach/callback if you need to:
template<typename TFuncSignature>
class Callback;
/////////////////
/* 2 ARGUMENT */
/////////////////
template<typename R, typename T1, typename T2>
class Callback<R (T1, T2)> {
public:
typedef R (*TFunc)(void*, T1, T2);
const static size_t Arity = 2;
Callback() : obj(0), func(0) {}
Callback(void* o, TFunc f) : obj(o), func(f) {}
R operator()(T1 t1, T2 t2) const {
return (*func)(obj, t1, t2);
}
typedef void* Callback::*SafeBoolType;
operator SafeBoolType () const {
return func != 0? &Callback::obj : 0;
}
bool operator! () const {
return func == 0;
}
bool operator== ( const Callback<R (T1, T2)>& right ) const {
return obj == right.obj && func == right.func;
}
bool operator!= ( const Callback<R (T1, T2)>& right ) const {
return obj != right.obj || func != right.func;
}
private:
void* obj;
TFunc func;
};
namespace detail {
template<typename R, class T, typename T1, typename T2>
struct DeduceConstMemCallback2 {
template<R(T::*Func)(T1, T2) const> inline static Callback<R(T1, T2)> Bind(T* o) {
struct _ { static R wrapper(void* o, T1 t1, T2 t2) { return (static_cast<T*>(o)->*Func)(std::forward<T1>(t1, t2); } };
return Callback<R(T1, T2)>(o, (R(*)(void*, T1, T2)) _::wrapper);
}
};
template<typename R, class T, typename T1, typename T2>
struct DeduceMemCallback2 {
template<R(T::*Func)(T1, T2)> inline static Callback<R(T1, T2)> Bind(T* o) {
struct _ { static R wrapper(void* o, T1 t1, T2 t2) { return (static_cast<T*>(o)->*Func)(t1, t2)); } };
return Callback<R(T1, T2)>(o, (R(*)(void*, T1, T2)) _::wrapper);
}
};
template<typename R, typename T1, typename T2>
struct DeduceStaticCallback2 {
template<R(*Func)(T1, T2)> inline static Callback<R(T1, T2)> Bind() {
struct _ { static R wrapper(void*, T1 t1, T2 t2) { return (*Func)(t1), t2); } };
return Callback<R(T1, T2)>(0, (R(*)(void*, T1, T2)) _::wrapper);
}
};
}
template<typename R, class T, typename T1, typename T2>
detail::DeduceConstMemCallback2<R, T, T1, T2> DeduceCallback2(R(T::*)(T1, T2) const) {
return detail::DeduceConstMemCallback2<R, T, T1, T2>();
}
template<typename R, class T, typename T1, typename T2>
detail::DeduceMemCallback2<R, T, T1, T2> DeduceCallback2(R(T::*)(T1, T2)) {
return detail::DeduceMemCallback2<R, T, T1, T2>();
}
template<typename R, typename T1, typename T2>
detail::DeduceStaticCallback2<R, T1, T2> DeduceCallback2(R(*)(T1, T2)) {
return detail::DeduceStaticCallback2<R, T1, T2>();
}
template <typename T1, typename T2> class Event2 {
public:
typedef void(* TSignature)(T1, T2);
typedef Callback<void(T1, T2)> TCallback;
typedef std::vector<TCallback> InvocationTable;
protected:
InvocationTable invocations;
public:
const static int ExpectedFunctorCount = 2;
Event2 () : invocations() {
invocations.reserve( ExpectedFunctorCount );
}
Event2 ( int expectedfunctorcount ) : invocations() {
invocations.reserve( expectedfunctorcount );
}
template <void (* TFunc)(T1, T2)> void Add ( ) {
TCallback c = DeduceCallback2( TFunc ).template Bind< TFunc >( );
invocations.push_back( c );
}
template <typename T, void (T::* TFunc)(T1, T2)> void Add ( T& object ) {
Add<T, TFunc>( &object );
}
template <typename T, void (T::* TFunc)(T1, T2)> void Add ( T* object ) {
TCallback c = DeduceCallback2( TFunc ).template Bind< TFunc >( object );
invocations.push_back( c );
}
template <typename T, void (T::* TFunc)(T1, T2) const> void Add ( T& object ) {
Add<T, TFunc>( &object );
}
template <typename T, void (T::* TFunc)(T1, T2) const> void Add ( T* object ) {
TCallback c = DeduceCallback2( TFunc ).template Bind< TFunc >( object );
invocations.push_back( c );
}
void Invoke ( T1 t1, T2 t2 ) {
size_t i;
for ( i = 0; i < invocations.size(); ++i ) {
invocations[i]( t1, t2 );
}
}
void operator() ( T1 t1, T2 t2 ) {
size_t i;
for ( i = 0; i < invocations.size(); ++i ) {
invocations[i]( t1, t2 );
}
}
size_t InvocationCount ( ) {
return invocations.size( );
}
template <void (* TFunc)(T1, T2)> bool Remove ()
{ return Remove (DeduceCallback2(TFunc).template Bind<TFunc>()); }
template <typename T, void (T::* TFunc)(T1, T2)> bool Remove (T& object)
{ return Remove <T, TFunc>(&object); }
template <typename T, void (T::* TFunc)(T1, T2)> bool Remove (T* object)
{ return Remove (DeduceCallback2(TFunc).template Bind<TFunc>(object)); }
template <typename T, void (T::* TFunc)(T1, T2) const> bool Remove (T& object)
{ return Remove <T, TFunc>(&object); }
template <typename T, void (T::* TFunc)(T1, T2) const> bool Remove (T* object)
{ return Remove (DeduceCallback2(TFunc).template Bind<TFunc>(object)); }
protected:
bool Remove( TCallback const& target ) {
auto it = std::find(invocations.begin(), invocations.end(), target);
if ( it == invocations.end())
return false;
invocations.erase(it);
return true;
}
};

Related

Variadic sequence of pointer to recursive member of struct/class as template parameter

I'm struggling with some template programming and I hope you can give me some help. I coded a C++11 interface that, given some structs like:
struct Inner{
double a;
};
struct Outer{
double x, y, z, r;
Inner in;
};
Implements a getter/setter to the real data that is customized to the specified struct members:
MyData<Outer, double, &Outer::x,
&Outer::y,
&Outer::z,
&Outer::in::a //This one is not working
> state();
Outer foo = state.get();
//...
state.set(foo);
I managed to implement this for simple structs in the following way:
template <typename T, typename U, U T::* ... Ms>
class MyData{
std::vector<U *> var;
public:
explicit MyData();
void set(T const& var_);
T get() const;
};
template <typename T, typename U, U T::* ... Ms>
MyData<T, U, Ms ... >::Struct():var(sizeof...(Ms))
{
}
template <typename T, typename U, U T::* ... Ms>
void MyData<T, U, Ms ...>::set(T const& var_){
unsigned i = 0;
for ( auto&& d : {Ms ...} ){
*var[i++] = var_.*d;
}
}
template <typename T, typename U, U T::* ... Ms>
T MyData<T, U, Ms ...>::get() const{
T var_;
unsigned i = 0;
for ( auto&& d : {Ms ...} ){
var_.*d = *var[i++];
}
return var_;
}
But it fails when I pass a member of a nested struct. Ideally, I'd like to implement a generic pointer to member type that allows me to be compatible with several levels of scope resolutions. I found this approach, but I'm not sure if this should be applied to my problem or if there exists some implementation ready to use. Thanks in advance!
Related posts:
Implicit template parameters
Pointer to inner struct
You might wrap member pointer into struct to allow easier chaining:
template <typename...> struct Accessor;
template <typename T, typename C, T (C::*m)>
struct Accessor<std::integral_constant<T (C::*), m>>
{
const T& get(const C& c) { return c.*m; }
T& get(C& c) { return c.*m; }
};
template <typename T, typename C, T (C::*m), typename ...Ts>
struct Accessor<std::integral_constant<T (C::*), m>, Ts...>
{
auto get(const C& c) -> decltype(Accessor<Ts...>().get(c.*m))
{ return Accessor<Ts...>().get(c.*m); }
auto get(C& c) -> decltype(Accessor<Ts...>().get(c.*m))
{ return Accessor<Ts...>().get(c.*m); }
};
template <typename T, typename U, typename ...Ts>
class MyData
{
std::vector<U> vars{sizeof...(Ts)};
template <std::size_t ... Is>
T get(std::index_sequence<Is...>) const
{
T res;
((Ts{}.get(res) = vars[Is]), ...); // Fold expression C++17
return res;
}
template <std::size_t ... Is>
void set(std::index_sequence<Is...>, T const& t)
{
((vars[Is] = Ts{}.get(t)), ...); // Fold expression C++17
}
public:
MyData() = default;
T get() const { return get(std::index_sequence_for<Ts...>()); }
void set(const T& t) { return set(std::index_sequence_for<Ts...>(), t); }
};
With usage similar to
template <auto ...ms> // C++17 too
using Member = Accessor<std::integral_constant<decltype(ms), ms>...>;
MyData<Outer, double, Member<&Outer::x>,
Member<&Outer::y>,
Member<&Outer::z>,
Member<&Outer::in, &Inner::a>
> state;
std::index_sequence is C++14 but can be implemented in C++11.
Folding expression from C++17 can be simulated too in C++11.
typename <auto> (C++17) should be replaced by typename <typename T, T value>.
Demo
A generalization of a member pointer is a function that can map T to X& at compile time.
In c++17 it isn't hard to wire things up thanks to auto. In c++11 it gets harder. But the basic idea is that you don't actually pass member pointers, you pass types, and those types know how to take your class and get a reference out of them.
template<class T, class D, class...Fs>
struct MyData {
std::array<D*, sizeof...(Fs)> var = {};
explicit MyData()=default;
void set(T const& var_) {
var = {{ Fs{}(std::addressof(var_))... }};
}
T get() {
T var_;
std::size_t index = 0;
using discard=int[];
(void)discard{ 0, (void(
*Fs{}(std::addressof(var_)) = *var[index++]
),0)... };
return var_;
}
};
it remains to write a utility that makes writing the Fs... easy for the member pointer case
template<class X, X M>
struct get_ptr_to_member_t;
template<class T, class D, D T::* M>
struct get_ptr_to_member_t< D T::*, M > {
D const* operator()( T const* t )const{
return std::addressof( t->*M );
}
};
#define TYPE_N_VAL(...) \
decltype(__VA_ARGS__), __VA_ARGS__
#define MEM_PTR(...) get_ptr_to_member_t< TYPE_N_VAL(__VA_ARGS__) >
now the basic case is
MyData< Outer, double, MEM_PTR(&Outer::x), MEM_PTR(&Outer::y) >
The more complex case can now be handled.
An approach would be to teach get_ptr_to_member to compose. This is annoying work, but nothing fundamental. Arrange is so that decltype(ptr_to_member_t * ptr_to_member_t) returns a type that instances right, applies it, then takes that pointer and runs the left hand side on it.
template<class First, class Second>
struct composed;
template<class D>
struct composes {};
#define RETURNS(...) \
noexcept(noexcept(__VA_ARGS__)) \
decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
template<class First, class Second>
struct composed:composes<composed<First, Second>> {
template<class In>
auto operator()(In&& in) const
RETURNS( Second{}( First{}( std::forward<In>(in) ) ) )
};
template<class First, class Second>
composed<First, Second> operator*( composes<Second> const&, composes<First> const& ) {
return {};
}
then we upgrade:
template<class X, X M>
struct get_ptr_to_member_t;
template<class T, class D, D T::* M>
struct get_ptr_to_member_t< D T::*, M >:
composes<get_ptr_to_member_t< D T::*, M >>
{
D const* operator()( T const* t )const{
return std::addressof( t->*M );
}
};
and now * composes them.
MyData<TestStruct, double, MEM_PTR(&Outer::x),
MEM_PTR(&Outer::y),
MEM_PTR(&Outer::z),
decltype(MEM_PTR(&Inner::a){} * MEM_PTR(&Outer::in){})
> state();
answre probably contains many typos, but design is sound.
In c++17 most of the garbage evaporates, like the macros.
I would use lambda approach to implement similar functionalities in C++17(C++14 is also ok, just change the fold expression):
auto access_by() {
return [] (auto &&t) -> decltype(auto) {
return decltype(t)(t);
};
}
template<class Ptr0, class... Ptrs>
auto access_by(Ptr0 ptr0, Ptrs... ptrs) {
return [=] (auto &&t) -> decltype(auto) {
return access_by(ptrs...)(decltype(t)(t).*ptr0);
};
}
auto data_assigner_from = [] (auto... accessors) {
return [=] (auto... data) {
return [accessors..., data...] (auto &&t) {
((accessors(decltype(t)(t)) = data), ...);
};
};
};
Let's see how to use these lambdas:
struct A {
int x, y;
};
struct B {
A a;
int z;
};
access_by function can be used like:
auto bax_accessor = access_by(&B::a, &A::x);
auto bz_accessor = access_by(&B::z);
Then for B b;, bax_accessor(b) is b.a.x; bz_accessor(b) is b.z. Value category is also preserved, so you can assign: bax_accessor(b) = 4.
data_assigner_from() will construct an assigner to assign a B instance with given accessors:
auto data_assigner = data_assigner_from(
access_by(&B::a, &A::x),
access_by(&B::z)
);
data_assigner(12, 3)(b);
assert(b.z == 3 && b.a.x == 12);

Termination issue on recursive template function in variadic template

I am trying to create a utility class that will call a specific function on all classes in a list. The purpose behind this is to automate an element of reflection within a hierarchy of classes.
I'm using Visual Studio 2015 to compile some C++ code and I'm getting a compile error when the recursive template function is unfolded because the compiler is having trouble distinguishing between the recursive function and the terminating function.
I've extracted out the core of the class to a simple test case:
#include <iostream>
template< typename ... BaseClasses >
class Meta
{
public:
virtual ~Meta() {}
template< typename T >
void call(const T& val)
{
callOnAllClasses<T, BaseClasses...>(val);
}
private:
template< typename T, typename HeadClass >
void callOnAllClasses(const T& val)
{
auto pObj = dynamic_cast<HeadClass*>(this);
if ( pObj )
pObj->HeadClass::doSomething(val);
}
template< typename T, typename HeadClass, typename ... TailClasses >
void callOnAllClasses(const T& val)
{
auto pObj = dynamic_cast<HeadClass*>(this);
if ( pObj )
pObj->HeadClass::doSomething(val);
callOnAllClasses<T, TailClasses...>(val);
}
};
class A
{
public:
void doSomething(int i)
{
std::cout << "A:" << i << std::endl;
}
};
class B
{
public:
void doSomething(int i)
{
std::cout << "B:" << i << std::endl;
}
};
class C : public B, public A, public Meta<C,B,A>
{
public:
void doSomething(int i)
{
std::cout << "C:" << i << std::endl;
}
};
int main()
{
C c;
c.call(5);
}
This results in the following error when compiled in Visual Studio 2015:
error C2668: 'Meta<C,B,A>::callOnAllClasses': ambiguous call to overloaded function
could be 'void Meta<C,B,A>::callOnAllClasses<T,A,>(const T &)'
or 'void Meta<C,B,A>::callOnAllClasses<T,A>(const T &)'
I've never used variadic templates before so I'm at a bit of a loss as to why this might be going wrong. Any help would be much appreciated!
You problem can be minimized as follows:
template< typename ... Bases >
struct Meta
{
template< typename T >
void call(const T& val)
{
callOnAllClasses<T, Bases...>(val);
}
template< typename T, typename HeadClass >
void callOnAllClasses(const T& val)
{
}
template< typename T, typename HeadClass, typename ... TailClasses >
void callOnAllClasses(const T& val)
{
callOnAllClasses<T, TailClasses...>(val);
}
};
struct C : Meta<int, int, int> { };
int main()
{
C{}.call(5);
}
When TailClasses is empty, both these signatures are ambiguous to the compiler:
template< typename T, typename HeadClass >
void callOnAllClasses(const T& val);
template< typename T, typename HeadClass, typename ... TailClasses >
void callOnAllClasses(const T& val);
Adding an extra template argument to the recursive case helps the compiler disambiguate between the variadic and non-variadic overloads when TailClasses is empty.
template< typename T, typename HeadClass, typename T1, typename ... TailClasses >
void callOnAllClasses(const T& val)
{
auto pObj = dynamic_cast<HeadClass*>(this);
if ( pObj )
pObj->HeadClass::doSomething(val);
callOnAllClasses<T, T1, TailClasses...>(val);
}
live example on godbolt

How To Combine Multiple std::function To One?

I have multiple std::function. Each of them have different input and output, and the input of one std::function might be the output of another std::function, which means that "serial" convert from one to another.
Maybe I can't describe it clear enough. Let code talks
std::function<bool(double)> combine(std::function<int(double)> convert1
, std::function<char(int)> convert2
, std::function<bool(char)> convert3)
{
return std::bind(convert1, convert2, convert3)//error. A function directly convert [double] to [bool] using convert1, convert2, convert3
}
Here is very simple code which I already remove the pointless code and show the core of my meaning.
So you can see convert1 do conversion from double to int, convert2 do conversion from int to char and convert3 do conversion from char to bool. Now I need to combine them together and so that I can directly convert double to bool.
And you know, I am not really want to convert double to bool. It's only for test.
One option to implement this is that write a help function:
bool helper(double d
, std::function<int(double)> convert1
, std::function<char(int)> convert2
, std::function<bool(char)> convert3)
{
return convert3(convert2(convert1(d)));
}
std::function<double(bool)> combine(std::function<int(double)> convert1
, std::function<char(int)> convert2
, std::function<bool(char)> convert3)
{
return helper;
}
But it's ugly code and maybe I use this conversion in a common way, which means that I should write this helper for all kind of my conversion.
So, is there a directly way to combine these function together?
you can use lambda expression to do this.
std::function<bool(double)> combine(std::function<int(double)> convert1
, std::function<char(int)> convert2
, std::function<bool(char)> convert3)
{
return [=](double d){return convert3(convert2(convert1(d)));}
}
Or you can use lambda directly in your code and do not use this combine function at all, also it would be more clear what happened.
If you still want use combine function and want a more generic one, maybe you can try something like this. (just a simple example)
template<typename Converter>
auto combineX(Converter converter){
return converter;
}
template<typename Converter, typename ...Converters>
auto combineX(Converter converter, Converters... converters){
return [converter,remain = combineX(converters...)](auto x){return remain(converter(x));};
}
Creating a simple type traits to extract the input type of the last function
template <typename, typename...>
struct lastFnType;
template <typename F0, typename F1, typename ... Fn>
struct lastFnType<F0, F1, Fn...>
{ using type = typename lastFnType<F1, Fn...>::type; };
template <typename T1, typename T2>
struct lastFnType<std::function<T2(T1)>>
{ using type = T1; };
you can transform the apple apple's solution (+1) in a more general variadic template recursive solution
template <typename T1, typename T2>
std::function<T1(T2)> combine (std::function<T1(T2)> conv)
{ return conv; }
template <typename T1, typename T2, typename T3, typename ... Fn>
std::function<T1(typename lastFnType<std::function<T2(T3)>, Fn...>::type)>
combine (std::function<T1(T2)> conv1, std::function<T2(T3)> conv2,
Fn ... fn)
{
using In = typename lastFnType<std::function<T2(T3)>, Fn...>::type;
return [=](In const & in){ return conv1(combine(conv2, fn...)(in)); };
}
But observe that the order of the converter is inverted (call with last used converter first; so combine(convert3, convert2, convert1))
The following is a full example
#include <functional>
template <typename, typename...>
struct lastFnType;
template <typename F0, typename F1, typename ... Fn>
struct lastFnType<F0, F1, Fn...>
{ using type = typename lastFnType<F1, Fn...>::type; };
template <typename T1, typename T2>
struct lastFnType<std::function<T2(T1)>>
{ using type = T1; };
template <typename T1, typename T2>
std::function<T1(T2)> combine (std::function<T1(T2)> conv)
{ return conv; }
template <typename T1, typename T2, typename T3, typename ... Fn>
std::function<T1(typename lastFnType<std::function<T2(T3)>, Fn...>::type)>
combine (std::function<T1(T2)> conv1, std::function<T2(T3)> conv2,
Fn ... fn)
{
using In = typename lastFnType<std::function<T2(T3)>, Fn...>::type;
return [=](In const & in){ return conv1(combine(conv2, fn...)(in)); };
}
int fn1 (double d)
{ return d*2.0; }
char fn2 (int i)
{ return i+3; }
bool fn3 (char c)
{ return c == 'a'; }
int main ()
{
std::function<int(double)> f1 { fn1 };
std::function<char(int)> f2 { fn2 };
std::function<bool(char)> f3 { fn3 };
auto cmb = combine(f3, f2, f1);
bool b { cmb(3.2) };
}
You may do:
template <typename T, typename F>
decltype(auto) apply(T&& t, F&& f)
{
return std::forward<F>(f)(std::forward<T>(t));
}
template <typename T, typename F, typename... Fs>
decltype(auto) apply(T&& t, F&& f, Fs&&... fs)
{
return apply(std::forward<F>(f)(std::forward<T>(t)), std::forward<Fs>(fs)...);
}
with usage:
apply(4,
[](int i) { return i * 10; },
[](auto i) {return i + 2;},
[](auto n){ return n / 10.f; })
Demo

Template non-type pointer to arbitrary class method

Let's say I have:
struct Foo {
void a();
void b(const int& );
int c();
};
I can create a function that takes as an argument an arbitrary pointer-to-Foo method:
template <typename R, typename... Formal, typename... Args>
R call(Foo* f, R (Foo::*method)(Formal...), Args&&... args) {
return (f->*method)(std::forward<Args>(args)...);
}
int gratuitous = call(&some_foo, &Foo::c);
And I can create a function that takes a specific type of pointer-to-Foo method as a template:
template <void (Foo::*method)()>
void only_for_a(Foo *f) {
(f->*method)();
}
only_for_a<&Foo::a>(&some_foo);
But is there a way to create a function that I can template on any pointer to class method? I want to be able to do:
works_for_anything<&Foo::a>(&some_foo);
works_for_anything<&Foo::b>(&some_foo, 42);
int result = works_for_anything<&Foo::c>(&some_foo);
Would this work for you?
template< typename T, T >
class works_for_anything_t;
template< typename R, typename... Args, R (*f)(Args...) >
class works_for_anything_t< R (*)(Args...), f >{
public:
R operator()( Args... args ){ return f(args...); }
};
template< typename T, typename R, typename... Args, R (T::*f)(Args...) >
class works_for_anything_t< R (T::*)(Args...), f >{
public:
R operator()( T& v, Args... args ) { return (v.*f)(args...); }
works_for_anything_t(T& v)
: v_(v) { }
private:
T& v_;
};
template< typename T, typename R, typename... Args, R (T::*f)(Args...) const >
class works_for_anything_t< R (T::*)(Args...) const, f >{
public:
R operator()( const T& v, Args... args ) const { return (v.*f)(args...); }
works_for_anything_t(const T& v)
: v_(v) { }
private:
const T& v_;
};
#define works_for_anything(f) works_for_anything_t<decltype(&f), &f>
struct Foo {
void a();
void b(const int& );
int c();
};
int test();
int main() {
Foo foo;
works_for_anything(Foo::b){foo}( 42 );
works_for_anything(test){}();
return 0;
}

5 years later, is there something better than the "Fastest Possible C++ Delegates"?

I know that the topic of "C++ delegates" has been done to death, and both http://www.codeproject.com and http://stackoverflow.com deeply cover the question.
Generally, it seems that Don Clugston's fastest possible delegate is the first choice for many people. There are a few other popular ones.
However, I noticed that most of those articles are old (around 2005) and many design choices seem to have been made taking in account old compilers like VC7.
I'm in need of a very fast delegate implementation for an audio application.
I still need it to be portable (Windows, Mac, Linux) but I only use modern compilers (VC9, the one in VS2008 SP1 and GCC 4.5.x).
My main criteria are:
it must be fast!
it must be forward-compatible with newer versions of the compilers. I have some doubts about that with Don's implementation because he explicitly states it's not standard-compliant.
optionally, a KISS-syntax and ease-of-use is nice to have
multicast would be nice, although I'm convinced it's really easy to build it around any delegate library
Furthermore, I don't really need exotic features. I just need the good old pointer-to-method thing. No need to support static methods, free functions or things like that.
As of today, what is the recommended approach? Still use Don's version?
Or is there a "community consensus" about another option?
I really don't want to use Boost.signal/signal2 because it's not acceptable in terms of performance. A dependency on QT is not acceptable as well.
Furthermore, I've seen some newer libraries while googling, like for example cpp-events but I couldn't find any feedback from users, including on SO.
Update: An article with the complete source code and a more detailed discussion has been posted on The Code Project.
Well, the problem with pointers to methods is that they're not all the same size. So instead of storing pointers to methods directly, we need to "standardize" them so that they are of a constant size. This is what Don Clugston attempts to achieve in his Code Project article. He does so using intimate knowledge of the most popular compilers. I assert that it's possible to do it in "normal" C++ without requiring such knowledge.
Consider the following code:
void DoSomething(int)
{
}
void InvokeCallback(void (*callback)(int))
{
callback(42);
}
int main()
{
InvokeCallback(&DoSomething);
return 0;
}
This is one way to implement a callback using a plain old function pointer. However, this doesn't work for methods in objects. Let's fix this:
class Foo
{
public:
void DoSomething(int) {}
static void DoSomethingWrapper(void* obj, int param)
{
static_cast<Foo*>(obj)->DoSomething(param);
}
};
void InvokeCallback(void* instance, void (*callback)(void*, int))
{
callback(instance, 42);
}
int main()
{
Foo f;
InvokeCallback(static_cast<void*>(&f), &Foo::DoSomethingWrapper);
return 0;
}
Now, we have a system of callbacks that can work for both free and member functions. This, however, is clumsy and error-prone. However, there is a pattern - the use of a wrapper function to "forward" the static function call to a method call on the proper instance. We can use templates to help with this - let's try generalizing the wrapper function:
template<typename R, class T, typename A1, R (T::*Func)(A1)>
R Wrapper(void* o, A1 a1)
{
return (static_cast<T*>(o)->*Func)(a1);
}
class Foo
{
public:
void DoSomething(int) {}
};
void InvokeCallback(void* instance, void (*callback)(void*, int))
{
callback(instance, 42);
}
int main()
{
Foo f;
InvokeCallback(static_cast<void*>(&f),
&Wrapper<void, Foo, int, &Foo::DoSomething> );
return 0;
}
This is still extremely clumsy, but at least now we don't have to write out a wrapper function every single time (at least for the 1 argument case). Another thing we can generalize is the fact that we're always passing a pointer to void*. Instead of passing it as two different values, why not put them together? And while we're doing that, why not generalize it as well? Hey, let's throw in an operator()() so we can call it like a function!
template<typename R, typename A1>
class Callback
{
public:
typedef R (*FuncType)(void*, A1);
Callback(void* o, FuncType f) : obj(o), func(f) {}
R operator()(A1 a1) const
{
return (*func)(obj, a1);
}
private:
void* obj;
FuncType func;
};
template<typename R, class T, typename A1, R (T::*Func)(A1)>
R Wrapper(void* o, A1 a1)
{
return (static_cast<T*>(o)->*Func)(a1);
}
class Foo
{
public:
void DoSomething(int) {}
};
void InvokeCallback(Callback<void, int> callback)
{
callback(42);
}
int main()
{
Foo f;
Callback<void, int> cb(static_cast<void*>(&f),
&Wrapper<void, Foo, int, &Foo::DoSomething>);
InvokeCallback(cb);
return 0;
}
We're making progress! But now our problem is the fact that the syntax is absolutely horrible. The syntax appears redundant; can't the compiler figure out the types from the pointer to method itself? Unfortunately no, but we can help it along. Remember that a compiler can deduce types via template argument deduction in a function call. So why don't we start with that?
template<typename R, class T, typename A1>
void DeduceMemCallback(R (T::*)(A1)) {}
Inside the function, we know what R, T and A1 is. So what if we can construct a struct that can "hold" these types and return them from the function?
template<typename R, class T, typename A1>
struct DeduceMemCallbackTag
{
};
template<typename R, class T, typename A1>
DeduceMemCallbackTag2<R, T, A1> DeduceMemCallback(R (T::*)(A1))
{
return DeduceMemCallbackTag<R, T, A1>();
}
And since DeduceMemCallbackTag knows about the types, why not put our wrapper function as a static function in it? And since the wrapper function is in it, why not put the code to construct our Callback object in it?
template<typename R, typename A1>
class Callback
{
public:
typedef R (*FuncType)(void*, A1);
Callback(void* o, FuncType f) : obj(o), func(f) {}
R operator()(A1 a1) const
{
return (*func)(obj, a1);
}
private:
void* obj;
FuncType func;
};
template<typename R, class T, typename A1>
struct DeduceMemCallbackTag
{
template<R (T::*Func)(A1)>
static R Wrapper(void* o, A1 a1)
{
return (static_cast<T*>(o)->*Func)(a1);
}
template<R (T::*Func)(A1)>
inline static Callback<R, A1> Bind(T* o)
{
return Callback<R, A1>(o, &DeduceMemCallbackTag::Wrapper<Func>);
}
};
template<typename R, class T, typename A1>
DeduceMemCallbackTag<R, T, A1> DeduceMemCallback(R (T::*)(A1))
{
return DeduceMemCallbackTag<R, T, A1>();
}
The C++ standard allows us to call static functions on instances (!):
class Foo
{
public:
void DoSomething(int) {}
};
void InvokeCallback(Callback<void, int> callback)
{
callback(42);
}
int main()
{
Foo f;
InvokeCallback(
DeduceMemCallback(&Foo::DoSomething)
.Bind<&Foo::DoSomething>(&f)
);
return 0;
}
Still, it's a lengthy expression, but we can put that into a simple macro (!):
template<typename R, typename A1>
class Callback
{
public:
typedef R (*FuncType)(void*, A1);
Callback(void* o, FuncType f) : obj(o), func(f) {}
R operator()(A1 a1) const
{
return (*func)(obj, a1);
}
private:
void* obj;
FuncType func;
};
template<typename R, class T, typename A1>
struct DeduceMemCallbackTag
{
template<R (T::*Func)(A1)>
static R Wrapper(void* o, A1 a1)
{
return (static_cast<T*>(o)->*Func)(a1);
}
template<R (T::*Func)(A1)>
inline static Callback<R, A1> Bind(T* o)
{
return Callback<R, A1>(o, &DeduceMemCallbackTag::Wrapper<Func>);
}
};
template<typename R, class T, typename A1>
DeduceMemCallbackTag<R, T, A1> DeduceMemCallback(R (T::*)(A1))
{
return DeduceMemCallbackTag<R, T, A1>();
}
#define BIND_MEM_CB(memFuncPtr, instancePtr) \
(DeduceMemCallback(memFuncPtr).Bind<(memFuncPtr)>(instancePtr))
class Foo
{
public:
void DoSomething(int) {}
};
void InvokeCallback(Callback<void, int> callback)
{
callback(42);
}
int main()
{
Foo f;
InvokeCallback(BIND_MEM_CB(&Foo::DoSomething, &f));
return 0;
}
We can enhance the Callback object by adding a safe bool. It's also a good idea to disable the equality operators since it's not possible to compare two Callback objects. Even better, is to use partial specialization to allow for a "preferred syntax". This gives us:
template<typename FuncSignature>
class Callback;
template<typename R, typename A1>
class Callback<R (A1)>
{
public:
typedef R (*FuncType)(void*, A1);
Callback() : obj(0), func(0) {}
Callback(void* o, FuncType f) : obj(o), func(f) {}
R operator()(A1 a1) const
{
return (*func)(obj, a1);
}
typedef void* Callback::*SafeBoolType;
operator SafeBoolType() const
{
return func != 0? &Callback::obj : 0;
}
bool operator!() const
{
return func == 0;
}
private:
void* obj;
FuncType func;
};
template<typename R, typename A1> // Undefined on purpose
void operator==(const Callback<R (A1)>&, const Callback<R (A1)>&);
template<typename R, typename A1>
void operator!=(const Callback<R (A1)>&, const Callback<R (A1)>&);
template<typename R, class T, typename A1>
struct DeduceMemCallbackTag
{
template<R (T::*Func)(A1)>
static R Wrapper(void* o, A1 a1)
{
return (static_cast<T*>(o)->*Func)(a1);
}
template<R (T::*Func)(A1)>
inline static Callback<R (A1)> Bind(T* o)
{
return Callback<R (A1)>(o, &DeduceMemCallbackTag::Wrapper<Func>);
}
};
template<typename R, class T, typename A1>
DeduceMemCallbackTag<R, T, A1> DeduceMemCallback(R (T::*)(A1))
{
return DeduceMemCallbackTag<R, T, A1>();
}
#define BIND_MEM_CB(memFuncPtr, instancePtr) \
(DeduceMemCallback(memFuncPtr).Bind<(memFuncPtr)>(instancePtr))
Usage example:
class Foo
{
public:
float DoSomething(int n) { return n / 100.0f; }
};
float InvokeCallback(int n, Callback<float (int)> callback)
{
if(callback) { return callback(n); }
return 0.0f;
}
int main()
{
Foo f;
float result = InvokeCallback(97, BIND_MEM_CB(&Foo::DoSomething, &f));
// result == 0.97
return 0;
}
I have tested this on the Visual C++ compiler (version 15.00.30729.01, the one that comes with VS 2008), and you do need a rather recent compiler to use the code. By inspection of the disassembly, the compiler was able to optimize away the wrapper function and the DeduceMemCallback call, reducing down to simple pointer assignments.
It's simple to use for both sides of the callback, and uses only (what I believe to be) standard C++. The code I've shown above works for member functions with 1 argument, but can be generalized to more arguments. It can also be further generalized by allowing support for static functions.
Note that the Callback object requires no heap allocation - they are of a constant size thanks to this "standardization" procedure. Because of this, it's possible to have a Callback object be a member of larger class, since it has a default constructor. It is also assignable (the compiler generated copy assignment functions are sufficient). It is also typesafe, thanks to the templates.
I wanted to follow off of #Insilico's answer with a bit of my own stuff.
Before I had stumbled upon this answer, I was trying to figure out fast callbacks as well that incurred no overhead and were uniquely comparable / identified by function signature only. What I ended up creating - with some serious help from Klingons Who Happened To Be at a BBQ - works for all function types (except Lambdas, unless you store the Lambda, but don't try it because it's really difficult and hard to do and may result in a robot proving to you how difficult it is and making you eat the shit for it). Thanks to #sehe, #nixeagle, #StackedCrooked, #CatPlusPlus, #Xeo, #DeadMG and of course #Insilico for the help in creating the event system. Feel free to use as you desire.
Anyway, an example is up on ideone, but the source code is also here for your use (because, since Liveworkspace went down, I don't trust them shady compiling services. Who knows when ideone will go down?!). I hope this is useful for somebody who's not busy Lambda/Function-objecting the world to pieces:
IMPORTANT NOTE: As of right now (28/11/2012, 9:35 PM) This variadic version will not work with the Microsoft VC++ 2012 November CTP (Milan). If you want to use it with that, you will have to get rid of all the variadic stuff and explicitly enumerate the number of arguments (and possibly template-specialize the 1-argument type for Event for void) to make it work. It's a pain, and I could only manage to write it out for 4 arguments before I got tired (and decided that passing more than 4 arguments was a bit of a stretch).
Source Example
Source:
#include <iostream>
#include <vector>
#include <utility>
#include <algorithm>
template<typename TFuncSignature>
class Callback;
template<typename R, typename... Args>
class Callback<R(Args...)> {
public:
typedef R(*TFunc)(void*, Args...);
Callback() : obj(0), func(0) {}
Callback(void* o, TFunc f) : obj(o), func(f) {}
R operator()(Args... a) const {
return (*func)(obj, std::forward<Args>(a)...);
}
typedef void* Callback::*SafeBoolType;
operator SafeBoolType() const {
return func? &Callback::obj : 0;
}
bool operator!() const {
return func == 0;
}
bool operator== (const Callback<R (Args...)>& right) const {
return obj == right.obj && func == right.func;
}
bool operator!= (const Callback<R (Args...)>& right) const {
return obj != right.obj || func != right.func;
}
private:
void* obj;
TFunc func;
};
namespace detail {
template<typename R, class T, typename... Args>
struct DeduceConstMemCallback {
template<R(T::*Func)(Args...) const> inline static Callback<R(Args...)> Bind(T* o) {
struct _ { static R wrapper(void* o, Args... a) { return (static_cast<T*>(o)->*Func)(std::forward<Args>(a)...); } };
return Callback<R(Args...)>(o, (R(*)(void*, Args...)) _::wrapper);
}
};
template<typename R, class T, typename... Args>
struct DeduceMemCallback {
template<R(T::*Func)(Args...)> inline static Callback<R(Args...)> Bind(T* o) {
struct _ { static R wrapper(void* o, Args... a) { return (static_cast<T*>(o)->*Func)(std::forward<Args>(a)...); } };
return Callback<R(Args...)>(o, (R(*)(void*, Args...)) _::wrapper);
}
};
template<typename R, typename... Args>
struct DeduceStaticCallback {
template<R(*Func)(Args...)> inline static Callback<R(Args...)> Bind() {
struct _ { static R wrapper(void*, Args... a) { return (*Func)(std::forward<Args>(a)...); } };
return Callback<R(Args...)>(0, (R(*)(void*, Args...)) _::wrapper);
}
};
}
template<typename R, class T, typename... Args>
detail::DeduceConstMemCallback<R, T, Args...> DeduceCallback(R(T::*)(Args...) const) {
return detail::DeduceConstMemCallback<R, T, Args...>();
}
template<typename R, class T, typename... Args>
detail::DeduceMemCallback<R, T, Args...> DeduceCallback(R(T::*)(Args...)) {
return detail::DeduceMemCallback<R, T, Args...>();
}
template<typename R, typename... Args>
detail::DeduceStaticCallback<R, Args...> DeduceCallback(R(*)(Args...)) {
return detail::DeduceStaticCallback<R, Args...>();
}
template <typename... T1> class Event {
public:
typedef void(*TSignature)(T1...);
typedef Callback<void(T1...)> TCallback;
typedef std::vector<TCallback> InvocationTable;
protected:
InvocationTable invocations;
public:
const static int ExpectedFunctorCount = 2;
Event() : invocations() {
invocations.reserve(ExpectedFunctorCount);
}
template <void (* TFunc)(T1...)> void Add() {
TCallback c = DeduceCallback(TFunc).template Bind<TFunc>();
invocations.push_back(c);
}
template <typename T, void (T::* TFunc)(T1...)> void Add(T& object) {
Add<T, TFunc>(&object);
}
template <typename T, void (T::* TFunc)(T1...)> void Add(T* object) {
TCallback c = DeduceCallback(TFunc).template Bind<TFunc>(object);
invocations.push_back(c);
}
template <typename T, void (T::* TFunc)(T1...) const> void Add(T& object) {
Add<T, TFunc>(&object);
}
template <typename T, void (T::* TFunc)(T1...) const> void Add(T* object) {
TCallback c = DeduceCallback(TFunc).template Bind<TFunc>(object);
invocations.push_back(c);
}
void Invoke(T1... t1) {
for(size_t i = 0; i < invocations.size() ; ++i) invocations[i](std::forward<T1>(t1)...);
}
void operator()(T1... t1) {
Invoke(std::forward<T1>(t1)...);
}
size_t InvocationCount() { return invocations.size(); }
template <void (* TFunc)(T1...)> bool Remove ()
{ return Remove (DeduceCallback(TFunc).template Bind<TFunc>()); }
template <typename T, void (T::* TFunc)(T1...)> bool Remove (T& object)
{ return Remove <T, TFunc>(&object); }
template <typename T, void (T::* TFunc)(T1...)> bool Remove (T* object)
{ return Remove (DeduceCallback(TFunc).template Bind<TFunc>(object)); }
template <typename T, void (T::* TFunc)(T1...) const> bool Remove (T& object)
{ return Remove <T, TFunc>(&object); }
template <typename T, void (T::* TFunc)(T1...) const> bool Remove (T* object)
{ return Remove (DeduceCallback(TFunc).template Bind<TFunc>(object)); }
protected:
bool Remove( TCallback const& target ) {
auto it = std::find(invocations.begin(), invocations.end(), target);
if (it == invocations.end())
return false;
invocations.erase(it);
return true;
}
};