Re[6]: Можно ли записать читабельнее?
От: rg45 СССР  
Дата: 10.04.23 15:08
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Так, хорош. Мы щас допилим до продакшена и будем постить в буст или сразу в комитет?


Ну, я уже разогнался, уже легче доехать, чем затормозить

Посмотри, как тебе такой вариант:

http://coliru.stacked-crooked.com/a/6652f4ea47751616

#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) { 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
}


overloaded — даже не класс, а простейший шаблон функции!

Единственное отличие — не возникает ошибки компиляции в случае отсутствия обработчика. Вместо этого возвращается false, что означает, что запрос не был обработан. Таким образом, и пустые цепочки обработчиков тоже возможны. В остальном результат в точности как у тебя.
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 10.04.2023 15:35 rg45 . Предыдущая версия . Еще …
Отредактировано 10.04.2023 15:25 rg45 . Предыдущая версия .
Отредактировано 10.04.2023 15:20 rg45 . Предыдущая версия .
Отредактировано 10.04.2023 15:17 rg45 . Предыдущая версия .
Отредактировано 10.04.2023 15:16 rg45 . Предыдущая версия .
Отредактировано 10.04.2023 15:16 rg45 . Предыдущая версия .
Отредактировано 10.04.2023 15:14 rg45 . Предыдущая версия .
Отредактировано 10.04.2023 15:13 rg45 . Предыдущая версия .
Re[7]: Можно ли записать читабельнее?
От: rg45 СССР  
Дата: 10.04.23 16:25
Оценка:
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", возникнут ошибки компиляции
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 10.04.2023 16:30 rg45 . Предыдущая версия .
Re[7]: Можно ли записать читабельнее?
От: Кодт Россия  
Дата: 10.04.23 16:36
Оценка: +2
Здравствуйте, rg45, Вы писали:

К>>Так, хорош. Мы щас допилим до продакшена и будем постить в буст или сразу в комитет?


R>Ну, я уже разогнался, уже легче доехать, чем затормозить


R>Посмотри, как тебе такой вариант:


Твой вариант имеет недостатки:

1) Инстанцируются все перегрузки, которые подошли по формальному признаку "сигнатура well-formed"

Например, функция-заглушка может выглядеть вот так
struct fuckup {
    void operator()(auto&&...) const {
        static_assert(false);
    }
};


Или, например, лесенка перегрузок может быть вот такой
[](Foo x, auto y) { ... },
[](Bar x, auto y) { ... }
[](auto x, Buz y) {
  // мы тут уверены, что x - ни Foo, ни Bar
  using X = decltype((x));
  static_assert(!is_same_v<X,Foo> && !is_same_v<X,Bar>);  // ну или ещё что-то, что ломает компиляцию
},
[](auto x, auto y) { ... }


2) Он жёстко приколочен к тому, что перегрузки возвращают void. Поэтому можно спокойно налепить bool поверх void.
Попробуй возвращать что-нибудь содержательное. Причём, возможно, для разных перегрузок — разное.

А у меня это — из коробки!
https://gcc.godbolt.org/z/8af5b79T4

R>overloaded — даже не класс, а простейший шаблон функции!


Переделать семейство функций-членов на семейство свободных функций — несложно.
Перекуём баги на фичи!
Re[8]: Можно ли записать читабельнее?
От: rg45 СССР  
Дата: 10.04.23 16:58
Оценка:
Здравствуйте, Кодт, Вы писали:

К>1) Инстанцируются все перегрузки, которые подошли по формальному признаку "сигнатура well-formed"


Согласен, это существенный недостаток.


К>2) Он жёстко приколочен к тому, что перегрузки возвращают void. Поэтому можно спокойно налепить bool поверх void.


Ну, в принципе, реализация не накладывает никаких ограничений на тип результата, он может быть каким угодно. Но результат теряется в моей реализации, это правда.
--
Справедливость выше закона. А человечность выше справедливости.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.