仅当(a)您正在调用函数/操作符的名称,或(b)将其强制转换为带有显式签名的指针(指向函数或成员函数)时,才会发生重载解析。
这里都没有发生。
std::function
接受与其签名兼容的任何对象。它并不需要专门的函数指针。(lambda不是std函数,std函数不是lambda)
现在,在我的自制函数变体中,出于这个原因,R(Args...)
我也接受签名R(*)(Args...)
(完全匹配)作为签名。但这意味着它将“完全匹配”签名提升到“兼容”签名之上。
核心问题是重载集不是C ++对象。您可以命名一个重载集,但不能“自然地”传递它。
现在,您可以创建一个函数的伪重载集合,如下所示:
#define RETURNS(...) \
noexcept(noexcept(__VA_ARGS__)) \
-> decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
#define OVERLOADS_OF(...) \
[](auto&&...args) \
RETURNS( __VA_ARGS__(decltype(args)(args)...) )
这将创建一个可以对函数名称进行重载解析的C ++对象。
扩展宏,我们得到:
[](auto&&...args)
noexcept(noexcept( baz(decltype(args)(args)...) ) )
-> decltype( baz(decltype(args)(args)...) )
{ return baz(decltype(args)(args)...); }
这很烦人。这里是一个更简单但实用性稍差的版本:
[](auto&&...args)->decltype(auto)
{ return baz(decltype(args)(args)...); }
我们有一个lambda,它可以接受任意数量的参数,然后完美地将它们转发给baz
。
然后:
class Bar {
std::function<void()> bazFn;
public:
Bar(std::function<void()> fun = OVERLOADS_OF(baz)) : bazFn(fun){}
};
作品。我们将重载分辨率推迟到存储在其中的lambda中fun
,而不是fun
直接传递重载集(它无法解析)。
至少有一种建议以C ++语言定义一种将函数名称转换为重载集对象的操作。在此类标准建议书成为标准之前,该OVERLOADS_OF
宏才有用。
您可以更进一步,并支持强制转换为兼容功能指针。
struct baz_overloads {
template<class...Ts>
auto operator()(Ts&&...ts)const
RETURNS( baz(std::forward<Ts>(ts)...) );
template<class R, class...Args>
using fptr = R(*)(Args...);
//TODO: SFINAE-friendly support
template<class R, class...Ts>
operator fptr<R,Ts...>() const {
return [](Ts...ts)->R { return baz(std::forward<Ts>(ts)...); };
}
};
但这开始变得钝了。
现场例子。
#define OVERLOADS_T(...) \
struct { \
template<class...Ts> \
auto operator()(Ts&&...ts)const \
RETURNS( __VA_ARGS__(std::forward<Ts>(ts)...) ); \
\
template<class R, class...Args> \
using fptr = R(*)(Args...); \
\
template<class R, class...Ts> \
operator fptr<R,Ts...>() const { \
return [](Ts...ts)->R { return __VA_ARGS__(std::forward<Ts>(ts)...); }; \
} \
}