I am looking into detail of a fastest C++ delegate posted on codeproject. (http://www.codeproject.com/cpp/ImpossiblyFastCppDelegate.asp). It seems the suggested implementation is at least a hundred times faster than boost::function in the case of copying and calling member function.
However, as it is stated in the original article, there were found to be several issues when compiling the suggested code in VC71 and VC8, while the same code compiled and run fine in gcc 3.4.2 or Intel C++ 9.1.
I discovered the following two issues are mostly causing compile errors in VC71 and VC8.
1) templater parameter can not be passed correctly into member template function as a portion of the signature of member function pointer of a non-type template parameter in partial template class. (Preferred syntax, so called, did not work in VC71 and VC8 due to this problem)
template<class T> class delegate;
template<class R, class T1> class delegate<R (T1)>
{
public:
template<class U, R (U::*TMFn)(T1)>
static delegate from_member(U * obj_ptr)
{
return delegate();
}
};
struct foo
{
void bar(int) { }
};
int main()
{
foo f;
delegate<void (int)>::from_member<foo, &foo::bar>( &f );
}
The above code snippet compile failed in VC71 and VC8 with the following error message.
main.cpp(112) : error C2440: 'specialization' : cannot convert from 'void (__thiscall foo::* )(int)' to 'R (__thiscall foo::* const )(T1)' Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast main.cpp(112) : error C2973: 'fd::delegate::from_member' : invalid template argument 'void (__thiscall foo::* )(int)' with [ T=void (int) ] main.cpp(81) : see declaration of 'fd::delegate::from_member' with [ T=void (int) ]
2) When overloaded member function pointer is given for the member template function as non-type template parameter, an incorrect value is passed and can cause run-time error or compile-time error when using the passed value.
#include <cstdlib>
#include <iostream>
using namespace std;
template<class R, class T1>
class delegate1
{
struct fxn_table
{
R (*invoke)(void *, T1);
};
void * obj_;
fxn_table * table_ptr_;
template<class T, R (T::*TMFn)(T1)> struct method_stub
{
static R invoke(void * obj, T1 a1)
{
return ( static_cast<T *>( obj )->*TMFn )( a1 );
}
};
template<class T, R (T::*TMFn)(T1)> struct table
{
static fxn_table * get()
{
static fxn_table static_table =
{
&method_stub<T, TMFn>::invoke,
};
return &static_table;
}
};
public:template<class T, R (T::*TMFn)(T1)>
static delegate1 from_method(T * obj)
{
delegate1 d;
d.table_ptr_ = table<T, TMFn>::get(); // (1)
d.obj_ = obj;
return d;
}
R operator ()(T1 a1) const
{
return ( *table_ptr_->invoke )( obj_, a1 );
}
};
struct foo
{
void bar(int) { std::cout << "foo::bar(int)" << std::endl; }
void foobar(int) { std::cout << "foo::foobar(int)" << std::endl; }
void foobar(char *) { std::cout << "foo::foobar(char *)" << std::endl; }
};
int main(int argc, char *argv[])
{
foo f;
delegate1<void, int> d1 = delegate1<void, int>::from_method<foo, &foo::bar>( &f );
d1( 1 );
delegate1<void, int> d2 = delegate1<void, int>::from_method<foo, &foo::foobar>( &f ); // (2) causes error C2975 at the line (1) above in VC8 and error C2563 in VC71
d2( 2 );
return 0;
}
The above code snippet is a variant of the original source code (which I am trying to improve features) but demonstrates that the following compile errors are being occurred in VC71 and VC8.
===== VC8 result =====
Compiling...
main.cpp
.\main.cpp(43) : error C2975: 'TMFn' : invalid template gument for 'delegate1<R,T1>::table', expected compile-time constant expression
with
[
R=void,
T1=int
]
.\main.cpp(26) : see declaration of 'TMFn'
.\main.cpp(69) : see reference to function template instantiation 'delegate1<R,T1> delegate1<R,T1>::from_method<foo,0>(T *)' being compiled
with
[
R=void,
T1=int,
T=foo
]
===== VC71 result =====
Compiling...
main.cpp
.\main.cpp(69) : error C2563: mismatch in formal parameter list
As clearly specified in the compile error messge above, non-type template parameter of member function poitner is passed as a value of '0' instead of the member function poitner to foo::foobar() when foobar() is an overloaded. Again, gcc 3.4.2 and Intel C++ 9.1 compiles and runs the same code without problem.
So I highly suspect that these are bugs of VC71 and VC8. right