I am trying to write my own delegate system as a replacement for boost::functions since the latter does a lot of heap-allocations which I profiled to be problematic.
I have written this as a replacement (simplified, the actual thing uses pooled memory and placement new but this is simple enough to reproduce the error):
template<class A, class B>
struct DelegateFunctor : public MyFunctor {
DelegateFunctor(void (*fptr)(A, B), A arg1, B arg2) : fp(fptr), a1(arg1), a2(arg2) {}
virtual void operator()() { fp(a1, a2); }
void (*fp)(A, B); // Stores the function pointer.
const A a1; const B a2; // Stores the arguments.
};
and this helper function:
template<class A, class B>
MyFunctor* makeFunctor(void (*f)(A,B), A arg1, B arg2) {
return new DelegateFunctor<A,B>(f, arg1, arg2);
}
The weird thing happens here:
void bar1(int a, int b) {
// do something
}
void bar2(int& a, const int& b) {
// do domething
}
int main() {
int a = 0;
int b = 1;
// A: Desired syntax and compiles.
MyFunctor* df1 = makeFunctor(&bar1, 1, 2);
// B: Desired syntax but does not compile:
MyFunctor* df2 = makeFunctor(&bar2, a, b);
// C: Not even this:
MyFunctor* df3 = makeFunctor(&bar2, (int&)a, (const int&)b);
// D: Compiles but I have to specify the whole damn thing:
MyFunctor* df4 = makeFunctor<int&, const int&>(&bar2, a, b);
}
The compiler error I get for version C (B is similar) is:
error: no matching function for call to ‘makeFunctor(void (*)(int&, const int&), int&, const int&)’
which is weird because the compiler has, in its error message, in fact correctly deduced the types.
Is there any way I can get version B to compile? How does boost::bind get around this limitation?
I’m using GCC 4.2.1. No C++11 solutions please.
Argument deduction strips off references. By matching the function pointer signature for
A, we want to getint &, but by matching the actual argument, we wantint, and so the deduction fails.One solution is to make the second type non-deduced, like so:
Now
AandBare determined purely by the function pointer’s signature:(Note that
std::common_type<T>::typeis the recommended idiom for the “identity type” whose sole purpose is to remove a template argument from argument deduction. This has previously been called things likeidentity<T>::typeoralias<T>, but the standard library traitstd::common_typeserves this purpose just fine.)