Reputation: 558
I am trying to implement the observer pattern with example usage as follows:
class Widget
{
class WidgetObserver
{
virtual void SomethingHappened(Widget&) { };
virtual void TextChanged(Widget&, const char*) { };
virtual void BoundsChanged(Widget&, const Rect&) { };
}
void AddObserver(WidgetObserver& observer)
{
observers.Add(observer);
}
virtual void OnSomthingHappened()
{
observers.Fire(&WidgetObserver::SomethingHappened, *this);
}
virtual void OnTextChanged(const char* text)
{
observers.Fire(&WidgetObserver::TextChanged, *this, text);
}
// Same for OnBoundsChanged(const Rect&)
ObserverList<Widget> observers;
}
class AnotherWidget : WidgetObserver
{
virtual void SomethingHappened(Widget& widget) override
{
std::cout << "Something happened with " widget.name() << std::endl;
}
// Implementations for TextChanged and BoundsChanged ...
}
void main()
{
Widget w;
AnotherWidget aw;
w.AddObserver(aw);
w.OnSomethingHappened();
}
Now my current (partial) implementation of ObserverList
is:
template <typename TObserver>
class ObserverList
{
std::vector<TObserver*> observer_list;
void AddObserver(TObserver& observer) { observer_list.push_back(&observer); }
template <typename ...TArgs>
void Fire(void(TObserver::*func)(TArgs...), TArgs&& args)
{
for (TObserver* ob : observer_list)
{
(ob->*func)(std::forward<TArgs>(args)...);
}
}
}
This works as expected with the functions SomethingHappened
and BoundsChanged
which both passes all its parameters by reference rather than by value, but with TextChanged
one of its parameters (const char* text
) is passed by value rather than reference. When I changed this to const char*& text
it compiles but as is it doesn't compile with MSVC++ 14.1 (Visual Studio 2017)
error C2672: 'ObserverList<Widget::WidgetObserver>::Fire': no matching overloaded function found
error C2782: 'void ObserverList<Widget::WidgetObserver>::Fire(void (__thiscall Widget::WidgetObserver::* )(TArgs...),TArgs &&...)': template parameter 'TArgs' is ambiguous
Seems like the compiler doesn't like parameters passed by value, is there any way to make it like them?
Upvotes: 0
Views: 624
Reputation: 13040
You can declare func
to have a simple type F
, i.e.
template <typename F, typename ...TArgs>
void Fire(F func, TArgs&&... args);
Upvotes: 1