Здравствуйте, Кодт, Вы писали:
К>Ну, можно сделать макрос.
К>К>#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; }
}
);
}