我正在尝试重新创建观察者模式,我可以完美地将参数转发给观察者的给定成员函数.
I am attempting to recreate the Observer pattern where I can perfectly forward parameters to a given member function of the observers.
如果我尝试传递具有多重覆盖的成员函数的地址,它无法根据参数推断出正确的成员函数.
If I attempt to pass the address of a member function which has multiple overrides, it cannot deduce the correct member function based on the arguments.
#include <iostream>
#include <vector>
#include <algorithm>
template<typename Class>
struct observer_list
{
template<typename Ret, typename... Args, typename... UArgs>
void call(Ret (Class::*func)(Args...), UArgs&&... args)
{
for (auto obj : _observers)
{
(obj->*func)(std::forward<UArgs>(args)...);
}
}
std::vector<Class*> _observers;
};
struct foo
{
void func(const std::string& s)
{
std::cout << this << ": " << s << std::endl;
}
void func(const double d)
{
std::cout << this << ": " << d << std::endl;
}
};
int main()
{
observer_list<foo> l;
foo f1, f2;
l._observers = { &f1, &f2 };
l.call(&foo::func, "hello");
l.call(&foo::func, 0.5);
return 0;
}
这无法编译,模板参数推导/替换失败.
请注意,我有 Args... 和 UArgs... 因为我需要能够传递不一定与类型相同的参数函数签名,但可以转换为所述类型.
Note that I had Args... and UArgs... because I need to be able to pass parameters which are not necessarily the same type asthe type of the function signature, but are convertible to said type.
我想我可以使用 std::enable_if<std::is_convertible<Args, UArgs>> 调用来消除歧义,但我不相信我可以用可变参数来做到这一点模板参数包?
I was thinking I could use a std::enable_if<std::is_convertible<Args, UArgs>> call to disambiguate, but I don't believe I can do this with a variadic template parameter pack?
我怎样才能让模板参数推导在这里起作用?
问题在这里:
l.call(&foo::func, "hello");
l.call(&foo::func, 0.5);
对于这两行,编译器不知道您指的是哪个 foo::func.因此,您必须通过强制转换提供缺少的类型信息(即 foo:func 的类型)来消除歧义:
For both lines, the compiler doesn't know which foo::func you are referring to. Hence, you have to disambiguate yourself by providing the type information that is missing (i.e., the type of foo:func) through casts:
l.call(static_cast<void (foo::*)(const std::string&)>(&foo::func), "hello");
l.call(static_cast<void (foo::*)(const double )>(&foo::func), 0.5);
或者,您可以提供编译器无法推导出的模板参数,这些参数定义了 func 的类型:
Alternatively, you can provide the template arguments that the compiler cannot deduce and that define the type of func:
l.call<void, const std::string&>(&foo::func, "hello");
l.call<void, double >(&foo::func, 0.5);
请注意,您必须使用 double 而不是上面的 const double.原因是一般double和const double是两种不同的类型.然而,在一种情况下 double 和 const double 被认为是相同的类型:作为函数参数.例如,
Notice that you have to use double and not const double above. The reason is that generally double and const double are two different types. However, there's one situation where double and const double are considered as if they were the same type: as function arguments. For instance,
void bar(const double);
void bar(double);
不是两个不同的重载而是实际上是同一个函数.
are not two different overloads but are actually the same function.
这篇关于消除作为模板参数传递的重载成员函数指针的歧义的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持html5模板网!
为什么两个函数的地址相同?Why do two functions have the same address?(为什么两个函数的地址相同?)
为什么 std::function 的初始化程序必须是可复制构Why the initializer of std::function has to be CopyConstructible?(为什么 std::function 的初始化程序必须是可复制构造的?)
混合模板与多态性mixing templates with polymorphism(混合模板与多态性)
我什么时候应该使用关键字“typename"?使用模When should I use the keyword quot;typenamequot; when using templates(我什么时候应该使用关键字“typename?使用模板时)
依赖名称解析命名空间 std/标准库Dependent name resolution amp; namespace std / Standard Library(依赖名称解析命名空间 std/标准库)
gcc 可以编译可变参数模板,而 clang 不能gcc can compile a variadic template while clang cannot(gcc 可以编译可变参数模板,而 clang 不能)