オーバーロードの解決は、(a)関数/演算子の名前を呼び出している場合、または(b)明示的なシグネチャを使用してそれを(関数またはメンバー関数への)ポインターにキャストしている場合にのみ発生します。
ここではどちらも発生していません。
std::function
シグネチャと互換性のあるオブジェクトを取得します。特に関数ポインタを取りません。(ラムダはstd関数ではなく、std関数はラムダではありません)
私の自作関数のバリアントでは、署名のために、この理由から引数(完全一致)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)...); }
任意の数の引数を取り、完全にそれらをに転送するラムダがありますbaz
。
次に:
class Bar {
std::function<void()> bazFn;
public:
Bar(std::function<void()> fun = OVERLOADS_OF(baz)) : bazFn(fun){}
};
動作します。オーバーロードセットを直接fun
渡すfun
(解決できない)代わりに、オーバーロードの解決をに格納するラムダに遅延させます。
関数名をオーバーロードセットオブジェクトに変換するC ++言語の操作を定義する提案が少なくとも1つあります。そのような標準的な提案が標準に入るまで、OVERLOADS_OF
マクロは役に立ちます。
さらに一歩進んで、cast-to-compatible-function-pointerをサポートできます。
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)...); }; \
} \
}