Skip to content

Latest commit

 

History

History
253 lines (204 loc) · 5.34 KB

226.md

File metadata and controls

253 lines (204 loc) · 5.34 KB
Info

  • Did you know about C++23 feature which adds support for inheriting from std::variant?

Example

struct value : std::variant<int, double> {
  using variant::variant;

  constexpr auto operator()(const auto& value) {
    std::clog << value << '\n';
  }
};

int main(){
  std::visit(value{}, std::variant<int, double>(42));  // prints 42
  std::visit(value{}, std::variant<int, double>(99.)); // prints 99
}

https://godbolt.org/z/oez6McKzn

Puzzle

  • Can you implement a generic state variant with id API (returns true if the given type is hold) and print_id which prints state id if available?
template<class... Ts>
class state; // TODO

const auto print_id = [] (auto& os); // TODO

int main(){
  using namespace boost::ut;

  struct disconnected {};
  struct connected { int id{}; };

  "inheriting from variant"_test = [] {
    state<disconnected, connected> state{};

    should("be disconnected and print nothing") = [=] {
      std::stringstream str{};
      mut(state) = disconnected{};
      std::visit(print_id(str), state);
      expect(state.is<disconnected>());
      expect(std::string{""} == str.str());
    };

    should("be connected and print id") = [=] {
      std::stringstream str{};
      mut(state) = connected{.id = 42};
      std::visit(print_id(str), state);
      expect(state.is<connected>());
      expect(std::string{"42"} == str.str());
    };
  };
}

https://godbolt.org/z/YPWcnYPsh

Solutions

template<class... Ts>
struct state : std::variant<Ts...> {
    template<class T>
    state& operator=(T&& t) noexcept {
        return (*this = state{t});
    }

    template<class T>
    bool is() const {
        return std::holds_alternative<T>(*this);
    }
};

const auto print_id = [] (auto& os) {
    return [&os] (const auto& st) {
        if constexpr (requires { st.id; }) {
            os << st.id;
        } else {
            os << "";
        }
    };
};

https://godbolt.org/z/ndK5jnT4W

template <class... Ts>
struct state : std::variant<Ts...> {
  using std::variant<Ts...>::operator=;

  template <typename T>
  [[nodiscard]] constexpr auto is() const noexcept -> bool {
    return std::holds_alternative<T>(*this);
  }
};

const auto print_id = [](auto& os) {
  return [&](const auto state) {
    if constexpr (requires { state.id; }) {
      os << state.id;
    }
  };
};

https://godbolt.org/z/7W5chhjY5

template<class... Ts>
class state : public std::variant<Ts...> {
  using base = std::variant<Ts...>;
  using base::base;

public:
  template <typename T>
  constexpr bool is() const { return holds_alternative<T>(*this); }
};

const auto print_id = [] (auto& os) {
  return [&] (const auto& member) {
    if constexpr (requires { member.id; }) {
      os << member.id;
    }
  };
};

https://godbolt.org/z/vM387vehn

template<class... Ts>
struct state : std::variant<Ts...> {
    using std::variant<Ts...>::variant;

    template <typename T>
    constexpr auto is() const noexcept -> bool {
        return std::holds_alternative<T>(*this);
    }
};

const auto print_id = [] (auto& os) {
    return [&] (auto const& state) {
        if constexpr (requires { state.id; }) {
            os << state.id;
        }
    };
};

https://godbolt.org/z/xx7zj3jzs

template<class... Ts>
class state : public std::variant<Ts...> {
public:
    using std::variant<Ts...>::variant;

    template <class T>
    constexpr auto is() const {
        return std::holds_alternative<T>(*this);
    }
};

const auto print_id = [] ([[maybe_unused]] auto& os) {
    return [&] (const auto& v) {
        if constexpr (requires { os << v.id; }) {
            os << v.id;
        }
    };
};

https://godbolt.org/z/r15dWoE6T

template<class... Ts>
struct state:std::variant<Ts...>
{
    using std::variant<Ts...>::variant;
    template<class T>
    constexpr bool is() const
    {
        return std::holds_alternative<T>(*this);
    }
};

const auto print_id (auto& os)
{
    return [&os](auto const & val){
        if constexpr ( requires { val.id; })
            os << val.id;
    };
}

https://godbolt.org/z/TYhej3xsa

template<class... Ts>
class state : public std::variant<Ts...> {
public:
    template<class C>
    bool is() const { return std::holds_alternative<C>(*this); }
    template<class T>
    state& operator=(T&& t) {
        std::variant<Ts...>::operator=(std::forward<T>(t));
        return *this;
     }
};

template<typename T> using Id_t = decltype(std::declval<T&>().id);
template<typename T> constexpr bool HasMember_id = std::experimental::is_detected_v< Id_t, T>;

const auto print_id = [] (auto& os) {
    return [&os]<typename T>(T const& t) {
        if constexpr(HasMember_id<T>)
            os << t.id;
    };
};

https://godbolt.org/z/dzY344zv1

template<class... Ts>
class state : public std::variant<Ts ...> {
public:
    using std::variant<Ts ...>::variant;

    template<class T>
    constexpr auto is() const{
        return std::holds_alternative<T>(*this);
    }
};

const auto print_id = [] (auto& os) {
    return [&](const auto & v){
        if constexpr (requires { v.id; })
            os << v.id;
    };
};

https://godbolt.org/z/q3x6Wv6j7