Reputation: 860
I'm trying to create a template function that accepts pointer to a member functions (non-virtual). I'm working with MSVC2010
The following code works when the problematic line is commented out. The error reported by compiler is pretty explanatory, but I wonder somehow still surprising. How would you recommend working around this problem.
Thanks!
class Foo{
public:
virtual void doFoo() {
std::cout << "In foo" << std::endl;
}
};
class Bar : public Foo{
public:
void doBar() {
std::cout << "In bar" << std::endl;
}
};
template<class A>
void caller(A &a, void (A::*func)()) {
(a.*func)();
}
int _tmain(int argc, _TCHAR* argv[])
{
Bar bar;
bar.doFoo();
caller(bar, &Bar::doBar);
caller(bar, &Bar::doFoo); // this line causes a compiler error
}
This fails on the following error.
error C2782: 'void caller(A &,void (__thiscall A::* )(void))' : template parameter 'A' is ambiguous
1> c:\test\test\test.cpp(23) : see declaration of 'caller'
1> could be 'Foo'
1> or 'Bar'
I can work around the error by changing caller to
template<class A, class B>
void caller(A &a, void (B::*func)()) {
(a.*func)();
}
But this introduces other subtle resolution bugs when considering overload resolutions. Ideally I'd like to only consider functions that can actually be applied to A.
Thanks!
Upvotes: 1
Views: 134
Reputation: 47762
You could use SFINAE to restrict the applicability of the second template
template<class A, class B>
void caller(A &a, void (B::*func)(), typename std::enable_if<std::is_base_of<B, A>::value, void>::type* =0)
This way, the overload will get out of the way for parameters that would cause a compile error otherwise. For reference, see std::is_base_of
.
Upvotes: 2
Reputation: 6118
As far as I can see it you must use unwanted version.
template<class A, class B>
void caller(A &a, void (B::*func)()) {
(a.*func)();
}
Because the function is not defined on that object and thus type resolution does not apply cleanly.
But I would generally not advise to use this type of callback schematic. Either use the good old C style callbacks; function with a void*
data pointer or something like sigc++.
The monster advantage with sigc++ is that you have generic signals that can be bound to almost anything, a function, a method or a fuctor and all typesafe.
(Please excuse that this is not a direct answer to your question, but a hint on how to take it further.)
Upvotes: 0