Разрешение перегрузки происходит только тогда, когда (а) вы вызываете имя функции / оператора или (б) приводите его к указателю (к функции или функции-члену) с явной подписью.
Здесь ничего не происходит.
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 ++, которая преобразует имя функции в объект набора перегрузки. Пока такое стандартное предложение не входит в стандарт,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)...); }; \
} \
}