Rozwiązanie problemu przeciążenia występuje tylko wtedy, gdy (a) wywołujesz nazwę funkcji / operatora lub (b) przesyłasz ją do wskaźnika (do funkcji lub funkcji członka) z wyraźną sygnaturą.
Tutaj też nie ma miejsca.
std::function
pobiera dowolny obiekt zgodny z jego podpisem. Nie bierze specjalnie wskaźnika funkcji. (lambda nie jest funkcją std, a funkcja std nie jest lambda)
Teraz w moich wariantach funkcji homebrew, do podpisu R(Args...)
akceptuję również R(*)(Args...)
argument (dokładne dopasowanie) właśnie z tego powodu. Ale oznacza to, że podnosi podpisy „ścisłe dopasowanie” ponad „zgodne” podpisy.
Podstawowym problemem jest to, że zestaw przeciążeń nie jest obiektem C ++. Możesz nazwać zestaw przeciążenia, ale nie możesz go przekazać „natywnie”.
Teraz możesz utworzyć zestaw pseudo-przeciążenia funkcji takiej jak ta:
#define RETURNS(...) \
noexcept(noexcept(__VA_ARGS__)) \
-> decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
#define OVERLOADS_OF(...) \
[](auto&&...args) \
RETURNS( __VA_ARGS__(decltype(args)(args)...) )
tworzy to pojedynczy obiekt C ++, który może rozwiązać problem przeciążenia dla nazwy funkcji.
Rozszerzając makra, otrzymujemy:
[](auto&&...args)
noexcept(noexcept( baz(decltype(args)(args)...) ) )
-> decltype( baz(decltype(args)(args)...) )
{ return baz(decltype(args)(args)...); }
irytujące do pisania. Prostsza, tylko nieco mniej użyteczna wersja jest tutaj:
[](auto&&...args)->decltype(auto)
{ return baz(decltype(args)(args)...); }
mamy lambda, która przyjmuje dowolną liczbę argumentów, a następnie doskonale je przekazuje baz
.
Następnie:
class Bar {
std::function<void()> bazFn;
public:
Bar(std::function<void()> fun = OVERLOADS_OF(baz)) : bazFn(fun){}
};
Pracuje. Odraczamy rozdzielczość przeciążenia do lambda, w którym przechowujemy fun
, zamiast przekazywać fun
bezpośrednio zestaw przeciążenia (którego nie może rozwiązać).
Istnieje co najmniej jedna propozycja zdefiniowania operacji w języku C ++, która konwertuje nazwę funkcji na obiekt zestawu przeciążenia. Dopóki taka standardowa propozycja nie będzie w standardzie, OVERLOADS_OF
makro jest przydatne.
Możesz pójść o krok dalej i wesprzeć wskaźnik cast-to-zgodny-funkcyjny.
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)...); };
}
};
ale to zaczyna być tępe.
Przykład na żywo .
#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)...); }; \
} \
}