問題描述
我正在嘗試重新創(chuàng)建觀察者模式,我可以完美地將參數(shù)轉(zhuǎn)發(fā)給觀察者的給定成員函數(shù).
I am attempting to recreate the Observer pattern where I can perfectly forward parameters to a given member function of the observers.
如果我嘗試傳遞具有多重覆蓋的成員函數(shù)的地址,它無(wú)法根據(jù)參數(shù)推斷出正確的成員函數(shù).
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;
}
這無(wú)法編譯,模板參數(shù)推導(dǎo)/替換失敗
.
請(qǐng)注意,我有 Args...
和 UArgs...
因?yàn)槲倚枰軌騻鬟f不一定與類型相同的參數(shù)函數(shù)簽名,但可以轉(zhuǎn)換為所述類型.
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>>
調(diào)用來(lái)消除歧義,但我不相信我可以用可變參數(shù)來(lái)做到這一點(diǎn)模板參數(shù)包?
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?
我怎樣才能讓模板參數(shù)推導(dǎo)在這里起作用?
推薦答案
問題在這里:
l.call(&foo::func, "hello");
l.call(&foo::func, 0.5);
對(duì)于這兩行,編譯器不知道您指的是哪個(gè) foo::func
.因此,您必須通過(guò)強(qiáng)制轉(zhuǎn)換提供缺少的類型信息(即 foo:func
的類型)來(lái)消除歧義:
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);
或者,您可以提供編譯器無(wú)法推導(dǎo)出的模板參數(shù),這些參數(shù)定義了 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);
請(qǐng)注意,您必須使用 double
而不是上面的 const double
.原因是一般double
和const double
是兩種不同的類型.然而,在一種情況下 double
和 const double
被認(rèn)為是相同的類型:作為函數(shù)參數(shù).例如,
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);
不是兩個(gè)不同的重載而是實(shí)際上是同一個(gè)函數(shù).
are not two different overloads but are actually the same function.
這篇關(guān)于消除作為模板參數(shù)傳遞的重載成員函數(shù)指針的歧義的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,也希望大家多多支持html5模板網(wǎng)!