2

I'm using JUCE as a x-platform framework, and I'm using template listener classes to map button/combobox etc. callbacks to certain handler functions. Since the different widgets have their own callback function name, I use the following structure:

template<typename Type, typename Widget>
class ListenerBase : public Widget::Listener
{
public:
  typedef void (Type::*TCallbackType)(void);
protected:
  void notifyCallback(Widget* notifier)
  {
  ...
  }
  void addHandler(Widget* notifier, TCallbackType callback)
  {
    notifier->addListener(this);
  ...
  }
};

template<typename Type>
class ButtonListenerHandler : public ListenerBase<Type, Button>
{
protected:
  void buttonClicked(Button* btn)
  {
     notifyCallback(btn);
  }
};

template<typename Type>
class LabelListenerHandler : public ListenerBase<Type, Label>
{
protected:
  void labelTextChanged(Label* lbl)
  {
     notifyCallback(lbl);
  }
};

And it works fine, as long as I use only one of the handler specializations in my class. As soon as I use more than one, VC++ 2008 complains of ambiguity between the addHandler calls as if the compiler cannot distiguish between addHandler(Button*, ...) and addHandler(Label*, ...) !! These functions are of different prototypes due to being templatized, so I have no idea why the compiler is giving me a hard time. Ideas ?

Edit due to requests:

A class with different listeners may look like:

class MyClass : public ButtonListenerHandler<MyClass>
              , public LabelListenerHandler<MyClass>
{
...
   void buttonHandlerFunction();
   void labelHandlerFunction();

   Button* m_btn;
   Label* m_label;
};

A where the error occurs:

MyClass::MyClass()
{
...
   addHandler(m_btn, &MyClass::buttonHandlerFunction);  <<< error
   addHandler(m_label, &MyClass::labelHandlerFunction);  <<< error
}

And the error is:

1>MyClass.cpp(287) : error C2385: ambiguous access of 'addHandler'
1>        could be the 'addHandler' in base 'ListenerBase<MyClass,juce::Button>'
1>        or could be the 'addHandler' in base 'ListenerBase<MyClass,juce::Label>'
Robert
  • 2,330
  • 29
  • 47

1 Answers1

0

Edit
Okay, after rethinking everything, the problem lies with ListenerBase<MyClass, Button> and ListenerBase<MyClass, Label> each defining an addHandler function, which because of inheritance doesn't seem to count as overloading, even though they have different signatures (one with a Button* parameter, the other with a Label* one). One possible fix I found for this is to fully qualify the call to addHandler, a bit verbose and maybe not what was really desired, but it works (for convenience, I typedef'd the base classes):

template<class Type>
class ButtonListenerHandler : public ListenerBase<Type, Button>{
public:
    typedef ListenerBase<Type, Button> ButtonListenerBase;
};

template<class Type>
class LabelListenerHandler : public ListenerBase<Type, Label>{
public:
    typedef ListenerBase<Type, Label> LabelListenerBase;
};

class MyClass : public ButtonListenerHandler<MyClass>,
                public LabelListenerHandler<MyClass>{
public:
    void buttonHandlerFunction();
    void labelHandlerFunction();

    MyClass(){
        ButtonListenerHandler<MyClass>::addHandler(m_btn, &MyClass::buttonHandlerFunction);
        LabelListenerHandler<MyClass>::addHandler(m_label, &MyClass::labelHandlerFunction);
    }

private:
    Button* m_btn;
    Label* m_label;
};

'nother Edit
Thanks to the fast answer to my question here, I can give it another edit. The using method mentioned there also applies to your problem. :)

class MyClass : public ButtonListenerHandler<MyClass>,
    public LabelListenerHandler<MyClass>{
public:
    using ButtonListenerHandler<MyClass>::addHandler;
    using LabelListener<MyClass>::addHandler;

    void buttonHandlerFunction(){
    }
    void labelHandlerFunction(){
    }

    MyClass(){
        addHandler(m_btn, &MyClass::buttonHandlerFunction);
        addHandler(m_label, &MyClass::labelHandlerFunction);
    }

private:
    Button* m_btn;
    Label* m_label;
};
Community
  • 1
  • 1
Xeo
  • 129,499
  • 52
  • 291
  • 397
  • ListenerBase is instantiated with different template arguments - they're different classes. Widget::Listener is the doubly inherited class. – Erik Mar 20 '11 at 12:26
  • @Erik: You're right, that was me acting a little too fast... let me overthink this one. – Xeo Mar 20 '11 at 12:30
  • @Erik: Updated, and funny enough, problem lies with exactly what you said "ListenerBase is instantiated with different template arguments - they're different classes.". :) – Xeo Mar 20 '11 at 12:51
  • @Xeo: Thanks, both options work fine but I find the second one (using ...) cleaner. But it does strike me as odd, or a bug even, that the compiler cannot distinguish between the addHandler methods without explicit "help"... – Robert Mar 21 '11 at 08:45
  • @Robert: See my linked question and the accepted answer, it's predefined by the standard. :/ – Xeo Mar 21 '11 at 20:12
  • @Xeo: Yes, I read that. Bummer, huh ? ;) Hope they fix it towards C++0x... :) – Robert Mar 22 '11 at 06:08