Небольшой c++ увеличить расширение на основе использованием Boost::property_tree


Это небольшое расширение на основе использованием Boost::property_tree, который поддерживает произвольные значения свойств и соответствующих сериализации. Он может быть использован в качестве альтернативы расширений в Qt и обеспечивает очень удобный способ для передачи свойств внутри вашего приложения.

Я хотел бы получить комментарий код от кого-то, просто указать, что я может быть делаю неправильно, потому что я не так хорош в C++ кодирования.

#include <boost/any.hpp>
#include <boost/variant.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ptree_serialization.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include <boost/property_tree/info_parser.hpp>

#include "core_defines.h"
#include "core_extensions_lexical_cast.h"

namespace boost {
namespace property_tree {

// Generic value holder, which will attempt to cast objects rather than
// indicate error if wrong type was supplied. This behavior is likely to
// be more error-prone, but is more 'user-friendly'. See 'strict_value_holder'
// class if you need strict type support.

// Supports trivial integral, floating point and string types in 'strict'
// mode and also allows the storage to hold arbitrary values using
// 'boost::any' storage. Note that due to implementation details, 
// values of specific (non-default) types can't be serialized
// (we skip them / replace with dummy objects).
class value_holder {
   // Main value holder type, which has support for common types
   // and can use the internal visitor for casting.
   typedef boost::variant<bool, int, unsigned, float, double,
                          std::string, std::wstring> Holder;
public:
   // Models 'DefaultConstructible', default constructor
   // leaves the storage uninitialized.
   value_holder() : using_any_holder_(false) { }

   template <typename T> value_holder(const T& value, typename boost::enable_if<
      typename boost::mpl::contains<Holder::types, T> >::type* = 0)
      : holder_(value), using_any_holder_(false) { }

   // Custom constructing routine for string-like types.
   explicit value_holder(const char* value)
      : holder_(std::string(value)), using_any_holder_(false) { }

   // Custom constructing routine for string-like types.
   explicit value_holder(const wchar_t* value)
      : holder_(std::wstring(value)), using_any_holder_(false) { }

   // Custom constructing routine for non-standard types.
   template <typename T> value_holder(const T& value, typename boost::disable_if<
      typename boost::mpl::contains<Holder::types, T> >::type* = 0)
      : any_holder_(value), using_any_holder_(true) { }

   // Retrieves held value with possible additional type casts.
   // Note that this method won't even compile for unsupported
   // types.
   template <typename T>
   typename boost::enable_if<typename boost::mpl::contains<Holder::types, T>, T>::type as() const {
      // Apply internal casting visitor.
      return boost::apply_visitor(type_casting_visitor<T>(), holder_);
   }

   // Attempts to retrieve non-standard type from internal 'boost::any'-based
   // storage. Throws 'boost::bad_any_cast' on errors.
   template <typename T>
   typename boost::disable_if<typename boost::mpl::contains<Holder::types, T>, T>::type as() const {
      // Apply internal 'boost::any_cast' routine.
      return boost::any_cast<T>(any_holder_);
   }

   // Generic holder swapping (required by 'boost::property_tree'
   // specification).
   void swap(value_holder& value) {
      holder_.swap(value.holder_);
      any_holder_.swap(value.any_holder_);
      std::swap(using_any_holder_, value.using_any_holder_);
   }

   // Check if current holder is empty (required by 
   // 'boost::property_tree' specification).
   bool empty() const {
      // Dispatch emptiness check based on currently
      // used value holder.
      if (using_any_holder_) return any_holder_.empty();

      return holder_.empty();
   }

private:
   // Internal functional object used to retrieve common types and perform
   // appropriate casting.
   template <typename T>
   struct type_casting_visitor : boost::static_visitor<T> {
      // Handles every possible arithmetic type with
      // 'boost::numeric_cast'.
      template <typename Y> T operator()(const Y& value) const {
         return boost::numeric_cast<T>(value);
      }

      // Template specialization for 'std::string' -> type casting
      template <> inline T operator()<std::string>(const std::string& value) const {
         return boost::lexical_cast<T>(value);
      }

      // Template specialization for 'std::wstring' -> type casting
      template <> inline T operator()<std::wstring>(const std::wstring& value) const {
         return boost::lexical_cast<T>(value);
      }
   };

   // Template specialization for type -> 'std::string' casting.
   template <> 
   struct type_casting_visitor<std::string> : boost::static_visitor<std::string> {
      template <typename Y> std::string operator()(const Y& value) const {
         return boost::lexical_cast<std::string>(value);
      }
   };

   // Template specialization for type -> 'std::wstring' casting.
   template <> 
   struct type_casting_visitor<std::wstring> : boost::static_visitor<std::wstring> {
      template <typename Y> std::wstring operator()(const Y& value) const {
         return boost::lexical_cast<std::wstring>(value);
      }
   };

public:
   // Custom serialization implementation.
   template <typename Archive> void serialize(Archive& ar, const unsigned int) {

      using namespace ::boost;

      ar & serialization::make_nvp("using_any_holder", using_any_holder_);

      // Serialize only what we can - if the value shares one
      // of the predefined types, use the default 'boost::variant'
      // serialization routine.
      if (!using_any_holder_) ar & serialization::make_nvp("holder", holder_);
   }

private:
   // Main value holder instance.
   Holder holder_;

   // Alternative value holder, which is used to store 
   // objects and data that differ from supported by main holder.

   // These can actually be treated as temporary objects, because
   // due to language / implementation limitations, they aren't
   // serialized / deserialized (it's impossible to combine benefits
   // from 'generics' while still having the strict typing - which
   // is a requirement for our serialization routines).
   boost::any any_holder_;

   // Indicates if the current value is actually using a 'boost::any'-
   // based value holder (non-common value).
   bool using_any_holder_;
};

// Strict variation of generic value holder, which
// does not support arbitrary types and will
// throw if types do not match exactly.
class strict_value_holder : public value_holder {
   // Main value holder type, which has support for common types.
   typedef boost::variant<bool, int, unsigned, float, double,
                          std::string, std::wstring> Holder;
public:
   // Models 'DefaultConstructible'.
   strict_value_holder() { }

   // Custom constructors for any of the available basic cases (which are
   // supported by initial 'boost::variant' placeholder).
   template <typename T> strict_value_holder(const T& value, typename boost::enable_if<
      typename boost::mpl::contains<Holder::types, T> >::type* = 0)
      : holder_(value) { }

   // Custom constructing routine for string-like types.
   explicit strict_value_holder(const char* value)
      : holder_(std::string(value)) { }

   // Custom constructing routine for string-like types.
   explicit strict_value_holder(const wchar_t* value)
      : holder_(std::wstring(value)) { }

   // Retrieves held value without any type casts. Throws 'boost::bad_get' if
   // casting was unsuccessful.
   template <typename T>
   typename boost::enable_if<typename boost::mpl::contains<Holder::types, T>, T>::type as() const {
      return boost::get<T>(holder_);
   }

   // Generic holder swapping (required by 'boost::property_tree'
   // specification).
   void swap(strict_value_holder& value) { holder_.swap(value.holder_); }

   // Check if current holder is empty (required by 
   // 'boost::property_tree' specification).
   bool empty() const { return holder_.empty(); }

public:
   // Custom serialization implementation.
   template <typename Archive> void serialize(Archive& ar, const unsigned int) {

      using namespace ::boost;

      // Serialize the value holder.
      ar & serialization::make_nvp("holder", holder_);
   }

private:
   // Main value holder instance.
   Holder holder_;
};

// Custom holder-based translator implementation.
template <typename T, typename Y> struct value_holder_translator {
   // Type definitions required by the
   // 'Translator' concept.
   typedef T internal_type;
   typedef Y external_type;

   boost::optional<Y> get_value(const T& value_holder) const {
      // Attempt to use casting routine
      // specific for template type.
      return value_holder.as<Y>();
   }

   boost::optional<T> put_value(const Y& value) const {
      // Construct appropriate value holder for specified
      // value (doesn't throw).
      return T(value);
   }
};

// Set custom translator for internal 'value_holder' type.
template <typename Y> struct translator_between<value_holder, Y> {
   typedef value_holder_translator<value_holder, Y> type;
};

// Set custom translator for internal 'strict_value_holder' type.
template <typename Y> struct translator_between<strict_value_holder, Y> {
   typedef value_holder_translator<strict_value_holder, Y> type;
};

} // namespace property_tree

// Type definition for custom holder-based properties collection. Note that
// for convenience, properties collection is brought to '::boost' namespace.

// This kind of properties allows arbitrary parameter types and, therefore,
// will substitute unsupported parameter types with dummies when writing. Also
// note, that if the parameter structure is filled from some xml-like file,
// you will lose the performance of custom value holder, because in this
// case parameters are stored as strings (that obviously brings a huge
// casting overhead to 'get<non-string-type>' operations).

// If you want to save the benefits of type checking and remove type casting
// overhead, use serialization instead of raw xml writing / reading.

typedef property_tree::basic_ptree<
   std::string, property_tree::value_holder> properties;

// This variation of properties structure supports
// wide character keys.
typedef property_tree::basic_ptree<
   std::wstring, property_tree::value_holder> wproperties;

// Bring property-specific path declaration into the '::boost'
// namespace.
using property_tree::path;
using property_tree::wpath;

// Enable custom tree-like format parsers.
using property_tree::xml_parser::write_xml;
using property_tree::xml_parser::read_xml;
using property_tree::json_parser::write_json;
using property_tree::json_parser::read_json;
using property_tree::ini_parser::write_ini;
using property_tree::ini_parser::read_ini;
using property_tree::info_parser::write_info;
using property_tree::info_parser::read_info;

} // namespace boost


3712
10
задан 12 апреля 2011 в 05:04 Источник Поделиться
Комментарии
1 ответ

Я думаю использовать boost::сериализации не являются хорошей идеей. Я читала про эту библиотеку (не все) и у них есть проблемы совместимости с предыдущими версиями.

Я писал другое имущество контейнер и диспетчере собственность несколько раз назад. И мы используем класс шаблона, без наддува, как это:

//Contains one property any complexity you want
template <typename Type>
class Property : public PropertyBase
{
protected:
Type m_property;
public:
/**
for deep copy you must define copy c-tor
@param Type const& prop - any property
**/
Property(Type const& prop)
:m_property(prop)
{
}
virtual ~Property() { }
public:
// @return Type const& - contained property
Type const& GetProperty() const { return m_property; }

/**
for deep copy you must define operator=
@param Type const& prop - any property
**/
void SetProperty(Type const& prop)
{
m_property = prop;
}
};

typedef PointerContainer<int, PropertyBase> TProperties; //list of properties for group
typedef PointerContainer<int, TProperties> TPropertyGroupList; //list of properties groups

//Class for manipulation with properies
class BasePropertyProvider
{
protected:
TPropertyGroupList m_propertyGroupList; // container of all properties
.................
public:
/**
@param int propertyGroup - group of properties for which we search
@param int propertyType - type of property which we search
@return Type const* - pointer on value or 0 if searching failed
**/
template <typename Type>
Type const* GetProperty(int propertyGroup, int propertyType) const;

/**
Add property in inner storage
@param int propertyGroup - group of properties for add
@param int propertyType - type of property for add
@param Type const & - reference on value for add
**/
template <typename Type>
void AddProperty(int propertyGroup, int propertyType, Type const &prop);
};

Это не полная реализация, но я думаю, что вы поняли направление.

Также я знаю, что Qt свойств решения. Вы можете найти его здесь.

Но они очень тяжелые инструменты, и если вы хотите, чтобы добавить некоторые оригинальные собственность необходимо написать 3 или 4 классов.

3
ответ дан 25 апреля 2011 в 10:04 Источник Поделиться