c++ - Efficient Value type -
i want create efficient , easy use value type. base of value
boost::variant
(and std::variant
in future), i'm new in it. , have questions:
- in code below, necessary use recursive variant?
- is possible not inherit
boost::variant
? maybe more efficient way exists? - do have comments or suggestions on code below (it's not completed code, draft)?
class value; typedef std::string string; typedef std::vector<char> bindata; typedef string url; typedef unsigned long long uid; tsw_strong_typedef(std::time_t, time) typedef std::vector<value> valuearray; typedef std::vector<string> stringarray; //typedef std::pair<string, value> namevalue; typedef std::list<value> valuelist; typedef std::list<string> stringlist; typedef std::map<string, string> stringstringmap; typedef std::map<string, value> namevaluemap; struct monostate { monostate() = default; }; constexpr bool operator<(monostate, monostate) noexcept { return false; } constexpr bool operator>(monostate, monostate) noexcept { return false; } constexpr bool operator<=(monostate, monostate) noexcept { return true; } constexpr bool operator>=(monostate, monostate) noexcept { return true; } constexpr bool operator==(monostate, monostate) noexcept { return true; } constexpr bool operator!=(monostate, monostate) noexcept { return false; } typedef monostate null; class object { public: object() = delete; object(const object &other) = default; object(object &&other); object(const string &name); object(string &&name); object(const string &name, const namevaluemap &fields); object(string &&name, const namevaluemap &fields); object(const string &name, namevaluemap &&fields); object(string &&name, namevaluemap &&fields); object &operator=(const object &other) = default; object &operator=(object &&other); public: const string &get_name() const; const namevaluemap &get_fields() const; public: bool operator<(const object &other) const noexcept; bool operator>(const object &other) const noexcept; bool operator<=(const object &other) const noexcept; bool operator>=(const object &other) const noexcept; bool operator==(const object &other) const noexcept; bool operator!=(const object &other) const noexcept; private: string name_; namevaluemap fields_; }; enum class valuetype { undefined, null, array, bindata, boolean, doublenumber, int64number, string, time, object }; // types ordnung need same valuetype ordnung. /// base value class typedef boost::variant<monostate, null, valuearray, bindata, bool, double, int64_t, string, time, object> valuebase; /** * @brief value class, implements common framework value. * * class container, can store multiple values, including values containers. * * @note * class based on variant class. may either boost::variant or std::variant in c++17 , higher. */ class value : public valuebase { public: using valuebase::valuebase; value() = default; value(const string::value_type *v) : valuebase(string(v)) {} public: bool is_array() const { return static_cast<valuetype>(which()) == valuetype::array; } bool is_bool() const { return static_cast<valuetype>(which()) == valuetype::boolean; } bool is_bindata() const { return static_cast<valuetype>(which()) == valuetype::bindata; } bool is_double() const { return static_cast<valuetype>(which()) == valuetype::doublenumber; } bool is_int64() const { return static_cast<valuetype>(which()) == valuetype::int64number; } bool is_null() const { return static_cast<valuetype>(which()) == valuetype::null; } bool is_object() const { return static_cast<valuetype>(which()) == valuetype::object; } bool is_string() const { return static_cast<valuetype>(which()) == valuetype::string; } bool is_time() const { return static_cast<valuetype>(which()) == valuetype::time; } bool is_undefined() const { return static_cast<valuetype>(which()) == valuetype::undefined; } public: bool as_bool() const { return as<bool>(); } bindata &as_bindata() { return as<bindata>(); } double as_double() const { return as<double>(); } int64_t as_int64() const { return as<int64_t>(); } object &as_object() { return as<object>(); } string &as_string() { return as<string>(); } time &as_time() { return as<time>(); } valuearray &as_array() { return as<valuearray>(); } public: valuetype value_type() const { return static_cast<valuetype>(which()); } public: template <typename t> const t& as() const { return boost::get<t>(*this); } template <typename t> t& as() { return boost::get<t>(*this); } template <typename t> const t& as(const t& default_value) const { return type() == typeid(t) ? boost::get<t>(*this) : default_value; } template <typename t> t& as(const t& default_value) { return type() == typeid(t) ? boost::get<t>(*this) : default_value; } template <typename t> boost::optional<t> as_optional() { return boost::make_optional(type() == typeid(t), as<t>()); } public: bool operator==(const valuebase &other) const { return valuebase::operator==(other); } bool operator<(const valuebase &other) const { return valuebase::operator<(other); } bool operator>(const valuebase &other) const { return !((*this) < other || (*this) == other); } bool operator<=(const valuebase &other) const { return ((*this) < other || (*this) == other); } bool operator>=(const valuebase &other) const { return !((*this) < other); } bool operator!=(const valuebase &other) const { return !((*this) == other); } private: // force compile error, prevent variant(bool) called value(void *) = delete; };
looks okay me.
you can without recursive variants iff standard library implementation allows instantiation of container classes incomplete types.
i'd note since tied base-class publicly, there nothing implementation can change without changing (binary) interface. therefore i'd surely implement members inline compiler optimize them without lto.
it not clear me to_x
members (possibly a<x>
possibly else depending on can_convert()
?). if it's wrap around as_<>
i'd rename them as_x()
etc.
you might want add optional<>
-like members like
template <typename t> t const& get_value_or(t const& default_value) const;
and possibly
template <typename t> optional<t> get() const; // boost optional can prevent copy²: template <typename t> optional<t const&> get() const;
this enables code like:
if (auto& s = value.get<string>()) { std::cout << "the string value '" << *s << "'\n"; } else { std::cout << "value has no string value\n"; }
¹ not - yet - standard specified. can use boost container instead promises this, non-allocating construction
² make sure not allow operation on rvalue, remove predictable class of errors, e.g.
template <typename t> optional<t const&> get()&& = delete;
Comments
Post a Comment