но я не смог заставить этих красавиц работать ...
В настоящее время невозможно заставить этих красавиц работать. Корень всего этого в том, что std::begin
и др. Не являются функциями. Это функциональные шаблоны . То есть они представляют не одну функцию, а целую семью. То же самое верно и в случае регулярных перегрузок. В тот момент, когда имя функции означает больше, чем одну функцию, оно не может быть передано. Перегрузочный набор - это не осязаемая вещь, которую мы можем передать как ссылку на тип или функцию. На самом деле это не вызываемый объект.
Заключение фактического перегруженного вызова в лямбду полностью обходит проблему. Потому что лямбда - это объект с типом, и его можно просто обойти. Это, по сути, снимает перегрузку с гражданства второго сорта. Но это идет с образцом.
Было выдвинуто предложение ( p1170 ) автоматически поднять набор перегрузки в вызываемый объект, но пока он, похоже, не набирает обороты. Таким образом, у C ++ 20 нет средств.
Что касается стандартного примера, мы можем сократить его, если мы хотим использовать макросы. Простой макрос, который корректно поднимает набор перегрузки, может выглядеть примерно так:
#define LIFT(...) [](auto&& ...args) \
noexcpet(noexcpet(__VA_ARGS__(std::forward<decltype(args)>(args)...))) \
-> decltype(auto) { \
return __VA_ARGS__(std::forward<decltype(args)>(args)...); \
}
Конечно, это само по себе много шаблонов, но он обрабатывает спецификацию исключений, а также вывод типа возврата для функций, которыене возвращать по значению. Это также идеально подходит для форвардов. Так что, хотя это действительно довольно уродливо, оно позволяет нам написать:
auto bg = make(LIFT(std::begin), a, b);