Yonatan
Yonatan

Reputation: 860

Template pointer to member base functions

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

Answers (2)

jpalecek
jpalecek

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

rioki
rioki

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

Related Questions