Resolusi kelebihan terjadi hanya ketika (a) Anda memanggil nama fungsi / operator, atau (b) melemparkannya ke pointer (berfungsi atau fungsi anggota) dengan tanda tangan eksplisit.
Tidak ada yang terjadi di sini.
std::function
mengambil objek apa pun itu kompatibel dengan tanda tangannya. Tidak memerlukan pointer fungsi secara khusus. (lambda bukan fungsi std, dan fungsi std bukan lambda)
Sekarang dalam varian fungsi homebrew saya, untuk tanda tangan R(Args...)
saya juga menerima R(*)(Args...)
argumen (pencocokan persis) untuk alasan ini. Tetapi itu berarti meningkatkan tanda tangan "kecocokan tepat" di atas tanda tangan "kompatibel".
Masalah intinya adalah bahwa set overload bukan objek C ++. Anda dapat memberi nama kumpulan kelebihan, tetapi Anda tidak dapat memutarnya "secara bawaan".
Sekarang, Anda dapat membuat set fungsi pseudo-overload seperti ini:
#define RETURNS(...) \
noexcept(noexcept(__VA_ARGS__)) \
-> decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
#define OVERLOADS_OF(...) \
[](auto&&...args) \
RETURNS( __VA_ARGS__(decltype(args)(args)...) )
ini menciptakan objek C ++ tunggal yang dapat melakukan resolusi kelebihan pada nama fungsi.
Memperluas makro, kita mendapatkan:
[](auto&&...args)
noexcept(noexcept( baz(decltype(args)(args)...) ) )
-> decltype( baz(decltype(args)(args)...) )
{ return baz(decltype(args)(args)...); }
yang menjengkelkan untuk menulis. Versi yang lebih sederhana, hanya sedikit kurang bermanfaat, ada di sini:
[](auto&&...args)->decltype(auto)
{ return baz(decltype(args)(args)...); }
kami memiliki lambda yang membutuhkan sejumlah argumen, kemudian menyempurnakannya baz
.
Kemudian:
class Bar {
std::function<void()> bazFn;
public:
Bar(std::function<void()> fun = OVERLOADS_OF(baz)) : bazFn(fun){}
};
bekerja. Kami menunda resolusi kelebihan ke dalam lambda yang kami simpan fun
, alih-alih lewatfun
set kelebihan beban secara langsung (yang tidak dapat diselesaikan).
Setidaknya ada satu proposal untuk mendefinisikan operasi dalam bahasa C ++ yang mengubah nama fungsi menjadi objek set yang kelebihan. Sampai proposal standar tersebut ada dalam standar, OVERLOADS_OF
makro berguna.
Anda bisa melangkah lebih jauh, dan mendukung 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)...); };
}
};
tapi itu mulai tumpul.
Contoh langsung .
#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)...); }; \
} \
}