Re[5]: Можно ли записать читабельнее?
От: Кодт Россия  
Дата: 08.04.23 22:38
Оценка:
Здравствуйте, rg45, Вы писали:

R>Так опрятнее, по-моему. И перфект-форвардинг референс в параметре снимает головную боль с контанстностью и lvalue-rvalue.


Это обсуждаемый момент.
Начиная с того, что автор кода может знать ожидаемую семантику foo — как минимум, какая там должна быть константность.

Ну и rvalue кортеж отдаст свои элементы как rvalue reference, которые внутри выражений станут неконстантными. Насколько это то, что нам надо?

Можно для надёжности обмазать форвардом:
#define FWD(arg) (std::forward<decltype(arg)>(arg))  // кстати, удобная и полезная конструкция

[](auto&& t, int) -> decltype(FWD(t).foo(0)) { return FWD(t).foo(0); }


Но опять же, этот код — демонстратор технологии, а не библиотека в продакшен.
Её есть куда вылизывать ещё дальше.

Мы даже вот такое можем сделать
#define TRY_EVAL(expr)  [](auto&& t, int) -> decltype(expr) { (expr); }


И ещё можно подумать, как сделать overloaded со строгим порядком предпочтений.

https://gcc.godbolt.org/z/4rrx4n1xc

#include <cstdio>
#include <type_traits>
#include <utility>
#include <tuple>

#define FWD(v) std::forward<decltype(v)>(v)

#define EXPLICITLY(expr) -> std::type_identity_t<decltype(expr)> { return expr; }
#define IMPLICITLY(expr) { return expr; }

template<size_t N> using index_t = std::integral_constant<size_t, N>;

template<class... Funs>
struct overloaded {
    std::tuple<Funs...> funs;
    overloaded(const Funs&... funs) : funs{funs...} {}

    static_assert(sizeof...(Funs) != 0);
    static constexpr size_t LAST = sizeof...(Funs) - 1;
    
    template<size_t I>
    auto call_(int, index_t<I> index, auto&&... x) const  // int предпочтительнее, чем long, но делаем SFINAE
    EXPLICITLY(std::get<I>(funs)(FWD(x)...))

    template<size_t I>
    decltype(auto) call_(long, index_t<I> index, auto&&... x) const
    IMPLICITLY(call_(0, index_t<I+1>{}, FWD(x)...))
    
    decltype(auto) call_(long, index_t<LAST> index, auto&&... x) const
    IMPLICITLY(std::get<index.value>(funs)(FWD(x)...))

    decltype(auto) operator()(auto&&... x) const
    IMPLICITLY(call_(0, index_t<0>{}, FWD(x)...))
};
template<class... Funs> overloaded(Funs...) -> overloaded<Funs...>;

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() {
    overloaded o {&foo, &bar, &buz, &def };

    printf("-----use:-----\n");
    o(123);
    o("xxx");
    o(&o);
    
    printf("-----misuse:-----\n");
    o(123.45);   // foo(123)
    o(nullptr);  // bar("(null)")
    
    printf("-----default:-----\n");
    o(&foo);
    o();
    o(1, 2, 3);
}
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.