std::visit для std::tuple

Олег Фатхиев
Олег Фатхиев

Предлагается добавить следующую функцию:

template <class Visitor, class Tuple>
constexpr /*see below*/ visit(Visitor&& v, Tuple&& t);

Где тип возвращаемого значения - это std::tuple со следующими подтипами:

std::invoke_result_t<Visitor&&, std::tuple_element<i, std::remove_cvref<Tuple>>>

Для i от 0 до std::tuple_size_v<std::remove_cvref<Tuple>> - 1.

Пример:

struct visiter {
    int operator()(int a) { return a * 2; }
    std::string operator(std::string b) { return b + b; }
};

std::tuple t{5, 6, 8, "abc"s, "def"s};

auto res = std::visit(visiter{}, t);

assert(res == std::tuple{10, 12, 16, "abcabc"s, "defdef"s};

Такое visit также удобно использовать с предлагаемым overloaded.

Возможная реализация:

template <class Visiter, class Tuple, std::size_t... Is>
constexpr auto visit(Visiter&& v, Tuple&& t, std::index_sequence<Ts...>) {
    return std::tuple{
        std::forward<Visiter>(v)(std::get<Is>(std::forward<Tuple>(t)))...
    };
}

template <class Visiter, class Tuple>
constexpr auto visit(Visiter&& v, Tuple&& t) {
    return visit_impl(std::forward<Visiter>(v), std::forward<Tuple>(t),
                      std::make_index_sequence<std::tuple_size_v<Tuple>>{});
}

Из-за сложности работы с функцие в случае, если visiter имеет void в качестве возвращаемого значения для какого-то из типов, возможно, будет лучше добавить следующую функцию:

template <class Visitor, class Tuple>
constexpr void visit(Visitor&& v, Tuple&& t);

Возможная реализация:

template <class Visiter, class Tuple, std::size_t... Is>
constexpr auto visit(Visiter&& v, Tuple&& t, std::index_sequence<Ts...>) {
    (..., std::forward<Visiter>(v)(std::get<Is>(std::forward<Tuple>(t))));
}

template <class Visiter, class Tuple>
constexpr void visit(Visiter&& v, Tuple&& t) {
    visit_impl(std::forward<Visiter>(v), std::forward<Tuple>(t),
               std::make_index_sequence<std::tuple_size_v<Tuple>>{});
}

 

 

4
рейтинг
3 комментария
Andrey Davydov

Вот же ж круто! А зачем?

Andrey Davydov
Олег Фатхиев

Andrey Davydov, бывает нужно пройтись по таплу как по гетерогенному контейнеру. Если представлять, что tuple - это контейнер, то можно считать, что visit - это своеобразный for_each для тапла

Олег Фатхиев
Andrey Davydov

Олег Фатхиев, это скорее transform а не for_each (в Boost.Hana так и называется), но я спрашивал, о каком-нибудь конкретном мотивирующем примере, потому что с tuple можно делать много разного (что и демонстрирует Boost.Hana) и не очень понятно, почему стандартизировать надо именно transform?

Andrey Davydov
Другие идеи
Группа создана, чтобы собирать предложения к стандарту C++, организовывать их внутренние обсуждения, помогать готовить их для отправки в комитет и защищать на общих собраниях в рабочей группе по С++ Международной организации по стандартизации (ISO).
Все предложения