Здравствуйте, Кодт, Вы писали:
К>Что мне в ней не нравится концептуально:
К>1) если есть несколько подходящих перегрузок с разными приоритетами, и у той, что подходит лучше (меньшее количество преобразований типа) приоритет ниже, — до неё дело не дойдёт
К>2) если есть несколько подходящих перегрузок с одним приоритетом, — ошибка неоднозначности трактуется как неудача подстановки
К>3) наличие/отсутствие ограничений (concept, requires) не пробрасывается из семейства перегрузок в полиморфную лямбду и может создавать неоднозначность (и см. пункт 2)
первые два момента получилось закрыть примерно так
#include <iostream>
template <std::size_t v> struct prio : prio<v-1> {};
template <> struct prio<0> {};
void f(prio<0>, short) {std::cout << "short" << std::endl;}
void f(prio<1>, int) {std::cout << "int" << std::endl;}
void f(prio<2>, long) {std::cout << "long" << std::endl;}
template<class... Args>
constexpr bool invocableWith = requires(Args... args) {{f(args...)};};
template <std::size_t pv=10, class... Args>
requires invocableWith<prio<pv>, Args...>
void dispatch(Args... args)
{
f(prio<pv>{}, args...);
}
template <std::size_t pv=10, class... Args>
requires (pv>0 && !invocableWith<prio<pv>, Args...>)
void dispatch(Args... args)
{
dispatch<pv-1>(args...);
}
template <std::size_t pv, class... Args>
requires (pv==0 && !invocableWith<prio<pv>, Args...>)
void dispatch(Args... args) = delete;
int main()
{
// выбор по второму аргументу
dispatch(short{});
dispatch(long{});
dispatch(int{});
// по второму аргументу коллизия, выбор по приоритету
dispatch(unsigned{});
dispatch(float{});
// нет вариантов
struct Bad{};
//dispatch(Bad{});
return 0;
}
https://gcc.godbolt.org/z/bTqzoWPWG