高效值类型



我想创建高效且易于使用的值类型。Value的基础是一个boost::variant(将来std::variant(,但我是新手。 我有一些问题:

  • 在下面的代码中,是否有必要使用递归变体?
  • 是否可以不从boost::variant继承?也许存在更有效的方法?
  • 您对下面的代码有什么意见或建议吗(它不是完全完成的代码,而只是一个草稿(?

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 to be same with ValueType ordnung.
/// Base for the Value class
typedef boost::variant<monostate, Null, ValueArray, BinData, bool, double, int64_t, String, Time, Object> ValueBase;

/**
* @brief The Value class, implements common framework value.
*
* This class is a container, which can store multiple values, including Values containers.
*
* @note
* Class based on a variant class. It may be either boost::variant or std::variant in C++17 and 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) to be called
Value(void *) = delete;
};

对我来说看起来还不错。

您可以不使用递归变体 IFF 您的标准库实现允许实例化不完整类型的容器类。

我会注意到,由于所有内容都公开绑定到基类,因此在不更改(二进制(接口的情况下,实现没有任何内容可以更改。因此,我肯定会内联实现所有成员,以便编译器即使没有 LTO 也能优化它们。

我不清楚to_X成员做什么(可能只是a<X>但可能还有其他事情取决于can_convert()?如果它只是一个环绕as_<>我会将它们重命名as_X()等等。

您可能还想添加类似optional<>的成员,例如

template <typename T> T const& get_value_or(T const& default_value) const;

而且可能

template <typename T> optional<T> get() const;
// with boost optional you can prevent a copy²:
template <typename T> optional<T const&> get() const;

这将启用如下代码:

if (auto& s = value.get<String>()) {
std::cout << "The string value is '" << *s << "'n";
} else {
std::cout << "Value has no string valuen";
}

¹ 这尚未指定标准。您可以随时使用 Boost 容器来代替它,它承诺了这一点,以及非分配构造

² 只需确保您不允许对右值进行操作,以删除可预测的错误类,例如

template <typename T> optional<T const&> get()&& = delete;

相关内容

  • 没有找到相关文章

最新更新