完美转发可变模板参数到成员函数
Perfect forwarding variadic template parameters to member function
我正在尝试使用示例用法实现观察者模式,如下所示:
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();
}
现在我的 ObserverList
当前(部分)实现是:
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)...);
}
}
}
这与函数 SomethingHappened
和 BoundsChanged
的预期一样工作,它们都通过引用而不是通过值传递其所有参数,但是 TextChanged
它的参数之一(const char* text
) 按值而不是引用传递。当我将其更改为 const char*& text
时,它会编译,但它不会用 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
好像编译器不喜欢按值传递参数,有什么办法让它喜欢它们吗?
您可以声明 func
具有简单类型 F
,即
template <typename F, typename ...TArgs>
void Fire(F func, TArgs&&... args);
我正在尝试使用示例用法实现观察者模式,如下所示:
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();
}
现在我的 ObserverList
当前(部分)实现是:
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)...);
}
}
}
这与函数 SomethingHappened
和 BoundsChanged
的预期一样工作,它们都通过引用而不是通过值传递其所有参数,但是 TextChanged
它的参数之一(const char* text
) 按值而不是引用传递。当我将其更改为 const char*& text
时,它会编译,但它不会用 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
好像编译器不喜欢按值传递参数,有什么办法让它喜欢它们吗?
您可以声明 func
具有简单类型 F
,即
template <typename F, typename ...TArgs>
void Fire(F func, TArgs&&... args);