Aşırı yük çözünürlüğü yalnızca (a) bir işlevin / operatörün adını çağırdığınızda veya (b) onu açık bir imzayla bir işaretçiye (işlev veya üye işlevine) dönüştürdüğünde gerçekleşir.
Burada da hiçbiri olmuyor.
std::function
imzasıyla uyumlu herhangi bir nesneyi alır . Özellikle bir işlev işaretçisi almaz. (lambda std işlevi değildir ve std işlevi lambda değildir)
Şimdi homebrew fonksiyon varyantlarımda, imza için de tam da bu nedenle R(Args...)
bir R(*)(Args...)
argümanı (tam eşleşme) kabul ediyorum . Ancak "tam eşleşme" imzalarını "uyumlu" imzaların üzerine çıkardığı anlamına gelir.
Temel sorun, bir aşırı yük kümesinin bir C ++ nesnesi olmamasıdır. Bir aşırı yük setini adlandırabilirsiniz, ancak "doğal" olarak geçemezsiniz.
Şimdi, böyle bir fonksiyonun sahte aşırı yük setini oluşturabilirsiniz:
#define RETURNS(...) \
noexcept(noexcept(__VA_ARGS__)) \
-> decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
#define OVERLOADS_OF(...) \
[](auto&&...args) \
RETURNS( __VA_ARGS__(decltype(args)(args)...) )
bu, işlev adında aşırı yük çözünürlüğü yapabilen tek bir C ++ nesnesi oluşturur.
Makroları genişleterek şunu elde ederiz:
[](auto&&...args)
noexcept(noexcept( baz(decltype(args)(args)...) ) )
-> decltype( baz(decltype(args)(args)...) )
{ return baz(decltype(args)(args)...); }
bu da yazmak için can sıkıcı bir durum. Daha basit, sadece biraz daha az kullanışlı bir sürüm burada:
[](auto&&...args)->decltype(auto)
{ return baz(decltype(args)(args)...); }
herhangi bir sayıda argüman alan bir lambdamız var, sonra onları mükemmel bir şekilde iletiyoruz baz
.
Sonra:
class Bar {
std::function<void()> bazFn;
public:
Bar(std::function<void()> fun = OVERLOADS_OF(baz)) : bazFn(fun){}
};
İşler. Aşırı yük çözünürlüğünü fun
, fun
bir aşırı yük setini doğrudan ( yerine çözemediği) geçmek yerine depoladığımız lambda'ya erteliyoruz .
C ++ dilinde bir işlev adını bir aşırı yük ayar nesnesine dönüştüren bir işlem tanımlamak için en az bir öneri vardır. Böyle bir standart teklif standartta olana kadar OVERLOADS_OF
makro yararlıdır.
Bir adım daha ileri gidebilir ve cast-uyumlu-fonksiyon-pointer'ı destekleyebilirsiniz.
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)...); };
}
};
ama bu genişlemeye başlıyor.
Canlı örnek .
#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)...); }; \
} \
}