R>Единственное отличие — не возникает ошибки компиляции в случае отсутствия обработчика. Вместо этого возвращается false, что означает, что запрос не был обработан. Таким образом, и пустые цепочки обработчиков тоже возможны. В остальном результат в точности как у тебя.
Хотя для того, чтобы вместо кода результата false получить ошибку компиляции, достаточно просто использовать констрейнт внутри функции overloaded. Следующий пример дает В ТОЧНОСТИ тот же эффект, что и твой:
http://coliru.stacked-crooked.com/a/c20f9298f6f339f5
#include <cstdio>
#include <type_traits>
#include <utility>
#include <tuple>
template <typename T> concept available = std::is_same_v<T, T>;
template <typename F>
struct callable_wrapper
{
F f;
template <typename...X>
std::true_type operator()(X&&...x) const requires available<decltype(f(x...))> { f(x...); return {}; }
template <typename...X>
std::false_type operator()(X&&...) const { return {}; }
};
template <typename...F>
auto overloaded(F&&...f)
{
return [=](auto&&...x) requires std::disjunction_v<decltype(callable_wrapper<F>{f}(x...))...>
{
return (callable_wrapper<F>{f}(x...) || ...);
};
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// Use case
void foo(int x) { printf("foo(%d)\n", x); }
void bar(const char* x) { printf("bar(\"%s\")\n", x); }
void buz(const void* x) { printf("buz(%p)\n", x); }
void def(...) { printf("def(...)\n"); }
int main()
{
const auto o = overloaded ( foo, bar, buz, def );
printf("-----use:-----\n");
o(123); // foo
o("xxx"); // bar
o(&o); // baz
printf("-----misuse:-----\n");
o(123.45); // foo
o(nullptr); // bar
printf("-----default:-----\n");
o(&foo); // def
o(); // def
o(1, 2, 3); // def
}
Теперь если убрать def из списка обработчиков, то в соответствующих точках вызова, которые помечены комментариями "def", возникнут ошибки компиляции