4

I'm writing a delegate class but it fails to take const member functions. Here is a test case :

class foo
{
    public:
   void MemberFunction()
   {
         printf("non const member function\n");
   }

   void ConstMemberFunction() const
   {
           printf("const member function\n");
   }
};

template <class C, void (C::*Function)()>
void Call(C* instance)
{
       (instance->*Function)();
}

int main (int argc, char** argv)
{
       foo bar;
       Call<foo,&foo::MemberFunction>(&bar);
       Call<foo,&foo::ConstMemberFunction>(&bar);
}

Now the compiler (visual studio 2010) gives me an error he cannot convert the const member function to a non-const function :

2>..\src\main.cpp(54): error C2440: 'specialization' : cannot convert from 'void (__cdecl foo::* )(void) const' to 'void (__cdecl foo::* const )(void)'
2>          Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
2>..\src\main.cpp(54): error C2973: 'Call' : invalid template argument 'void (__cdecl foo::* )(void) const'
2>          ..\src\main.cpp(37) : see declaration of 'Call'

ok, easy fix (I though :P ) by adding this :

template <class C, void (C::*Function)() const>
void Call(C* instance)
{
    (instance->*Function)();
}

but now the compiler is completly confused (and me with it). it looks like he now tries to use the const function for the non-const member function and the non-const function for the const member function.

2>..\src\main.cpp(53): error C2440: 'specialization' : cannot convert from 'void (__cdecl foo::* )(void)' to 'void (__cdecl foo::* const )(void) const'
2>          Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
2>..\src\main.cpp(53): error C2973: 'Call' : invalid template argument 'void (__cdecl foo::* )(void)'
2>          ..\src\main.cpp(43) : see declaration of 'Call'
2>..\src\main.cpp(53): error C2668: 'Call' : ambiguous call to overloaded function
2>          ..\src\main.cpp(43): could be 'void Call<foo,void foo::MemberFunction(void)>(C *)'
2>          with
2>          [
2>              C=foo
2>          ]
2>          ..\src\main.cpp(37): or       'void Call<foo,void foo::MemberFunction(void)>(C *)'
2>          with
2>          [
2>              C=foo
2>          ]
2>          while trying to match the argument list '(foo *)'
2>..\src\main.cpp(54): error C2440: 'specialization' : cannot convert from 'void (__cdecl foo::* )(void) const' to 'void (__cdecl foo::* const )(void)'
2>          Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
2>..\src\main.cpp(54): error C2973: 'Call' : invalid template argument 'void (__cdecl foo::* )(void) const'
2>          ..\src\main.cpp(37) : see declaration of 'Call'
2>..\src\main.cpp(54): error C2668: 'Call' : ambiguous call to overloaded function
2>          ..\src\main.cpp(43): could be 'void Call<foo,void foo::ConstMemberFunction(void) const>(C *)'
2>          with
2>          [
2>              C=foo
2>          ]
2>          ..\src\main.cpp(37): or       'void Call<foo,void foo::ConstMemberFunction(void) const>(C *)'
2>          with
2>          [
2>              C=foo
2>          ]
2>          while trying to match the argument list '(foo *)'

If I would rename the second Call function (with the const), it all works fine but I would rather use one function.

So, can anybody point me towards what I'm doing wrong and how I can make this work ?

Thx!

1
  • This should work, tell MS they're wrong. Commented Jun 18, 2012 at 20:08

3 Answers 3

3

I think you might be able to address this by removing the function pointer from the template type signature and instead relying on overloading:

template <class C>
    void Call(C* ptr, void (C::*function)()) {
    (ptr->*function)();
}
template <class C>
    void Call(C* ptr, void (C::*function)() const) {
    (ptr->*function)();
}

This now uses normal function overloading to select which of the two functions should be called. const member function pointers will call down to the second version, while non-const functions will call up to the first version. This also means that you don't need to explicitly provide any type information to the template function; the compiler can deduce C in both contexts.

Let me know if (1) this doesn't work or (2) this does work, but isn't what you want.

Hope this helps!

Sign up to request clarification or add additional context in comments.

1 Comment

Thx for the answer! This does work perfectly in my test case but now my delegate class doesn't compile anymore (tries to take '&' of an l-value reference), but that's a completly different issue and nothing to do with this question :)
1

Use std::bind or lambdas, which VS2010 supports, and std::function and this will cease to be a problem for you.

Comments

0

Your problem is that a member function pointer is a different type than a const member function pointer. I modified your Call function to this:

template< typename C, typename funcptr_t, funcptr_t ptr >
void Call( C *instance )
{
  (instance->*ptr)();
}

and now using the additional template parameter, I can call it like this:

Call<foo,void (foo::*)(),&foo::MemberFunction>(&bar);
Call<foo,void (foo::*)() const, &foo::ConstMemberFunction>(&bar);

That's a bit messy, though. The overloading solution is better! :-)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.