問題描述
我正在嘗試重新創建觀察者模式,我可以完美地將參數轉發給觀察者的給定成員函數.
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模板網!