Re[2]: Можно ли записать читабельнее?
От: rg45 СССР  
Дата: 07.04.23 20:37
Оценка: 9 (1)
Здравствуйте, Кодт, Вы писали:

К>Ну, можно сделать макрос.

К>
К>#define DECLARE_HAS_MEMBER(member) \
К>struct has_##member { \
К>    template<class T, class = void> struct test : std::false_type {}; \
К>    template<class T> struct test<T, std::void_t<decltype(&T::member)>> : std::true_type {}; \
К>}; \
К>// endmacro

К>#define HAS_MEMBER(type, member) (has_##member::template test<std::decay_t<type>>::value)

К>DECLARE_HAS_MEMBER(foo)
К>DECLARE_HAS_MEMBER(bar)
К>


К>А функцию-визитёр — лямбдой

К>
К>visit(your_tuple,
К>  [](auto&& t) {
К>    if constexpr (HAS_MEMBER(decltype(t), foo)) { t.foo(123); }
К>    if constexpr (HAS_MEMBER(decltype(t), bar)) { t.bar("hello"); }
К>    // можно if-else, можно какую угодно логику
К>  }
К>);
К>



А вот если взять за основу подход
Автор: sergii.p
Дата: 04.04.23
, который предложил sergii.p, то все получается гораздо элегантнее — без всяких макросов и метафункций:

http://coliru.stacked-crooked.com/a/765467d6116e090e

#include <tuple>
#include <iostream>

// определение функции visit
template<typename T, typename V, size_t... I>
void visit_impl(T&& t, V&& v, std::index_sequence<I...>)
{
    (..., v(std::get<I>(t)));
}

template<typename T, typename V>
void visit(T&& t, V&& v)
{
    visit_impl(std::forward<T>(t), std::forward<V>(v),
        std::make_index_sequence<std::tuple_size<
            typename std::decay<T>::type>::value>());
}

// вспомогательный тип для visitor
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;


/////////////////////////////////////////////////////////////////////////////
// Test case

struct HasFoo
{
    void foo() const { std::cout << "HasFoo::foo()" << std::endl; }
};

struct HasBar
{
    void bar() const { std::cout << "HasBar::bar" << std::endl; }
};

struct HasNothing
{
};

int main()
{
    visit(std::make_tuple(HasFoo{}, HasBar{}, HasNothing{}),
        overloaded {
            [](auto&& t) -> decltype(t.foo()) { return t.foo(); },
            [](auto&& t) -> decltype(t.bar()) { return t.bar(); },
            [](...){ std::cout << "Has neither foo nor bar" << std::endl; }
        }
    );
}
--
Справедливость выше закона. А человечность выше справедливости.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.