Skip to content

Latest commit

 

History

History
99 lines (76 loc) · 2.61 KB

353.md

File metadata and controls

99 lines (76 loc) · 2.61 KB
Info

Example

template<class... Ts>
struct inc {
    std::variant<Ts...> v{};

    auto operator++() {
        std::visit([&](auto& v) { ++v; }, v);
    }

    template<class T>
    operator T() const {
        T result{};
        std::visit(
            overloaded{
                [&](T v) { result = v; },
                [](auto&&) {}
            }
        , v);
        return result;
    }
};

auto visit(std::int16_t size, std::int32_t iterations) {
    auto it = inc<std::int8_t, std::int16_t, std::int32_t>{size};

    for (auto i = 0; i < iterations; ++i, ++it)
        ;

    return std::int16_t(it);
}

https://godbolt.org/z/1813rceKv

Puzzle

  • **Can you implement different versions of std::visit dispatching and compare its performance?

    • generated switch case
    • jump table
    • fold expression
    • if/else
    • generted goto
    • ...
constexpr auto visit(auto&& f, auto&& v); // TODO

https://godbolt.org/z/eac6YarnG

Solutions

template<class F, class V, class R, std::size_t N, std::size_t Size>
constexpr auto visit_impl([[maybe_unused]] F&& f, [[maybe_unused]] V&& v) -> R {
  if constexpr (N < Size) {
    switch (v.index()) {
      default:
        return visit_impl<F, V, R, N+1, Size>(std::forward<F>(f), std::forward<V>(v));
      case N:
        return std::forward<F>(f)(std::get<N>(std::forward<V>(v)));
    }
  } else {
    __builtin_unreachable();
  }
}

template<class F, class V, template<class...> class T, class... Ts>
auto result_type(T<Ts...>&&) ->
  std::common_type_t<decltype(std::declval<F>()(std::get<Ts>(std::declval<V>())))...>;

template<class F, class V, template<class...> class T, class... Ts>
auto result_type(T<std::monostate, Ts...>&&) ->
  std::common_type_t<decltype(std::declval<F>()(std::get<Ts>(std::declval<V>())))...>;

template<class F, class V>
constexpr decltype(auto) visit(F&& f, V&& v) {
  using variant_t = std::remove_const_t<std::remove_reference_t<V>>;
  constexpr auto size = std::variant_size_v<variant_t>;
  static_assert(size > 0, "Empty variant is not supported!");
  using result_t = decltype(result_type<F, V>(std::declval<variant_t>()));
  return visit_impl<F, V, result_t, 0u, size>(std::forward<F>(f), std::forward<V>(v));
}

https://godbolt.org/z/YPqGzKP95