Розв’язання перевантаження виникає лише тоді, коли (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 ++, яка перетворює ім'я функції в об'єкт набору перевантажень. Поки така стандартна пропозиція не є стандартною, 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)...); }; \
} \
}