1

JSON構造を保存する方法を探しています

{
    "foo" : "FOO" ,
    "fuu" : "FUU" ,

    "bar" :
    {
        "no"  : "abc" ,
        "yes" : "ABC"
    } ,

    "baa" :
    {
        "no"  : "xyz" ,
        "yes" : "XYZ"   
    }
}

によって初期化された C++ のマップとしてboost::assign:::map_list_of。このようなもの

const std::map<UNKNOWN_TYPE_INVOLVING_VARIANT> = boost::assign::map_list_of
    {
        { "foo" , "FOO" } ,
        { "fuu" , "FUU" } ,
        { "bar" ,
            { "no"  , "abc" } ,
            { "yes" , "ABC" }
        } ,
        { "baa" ,
            { "no"  , "xyz" } ,
            { "yes" , "XYZ" }
        }   
    };

一部のキーは文字列にマップされ、他のキーはサブマップにマップされます (hello variant)。私は C++03 に限定されており、Boost Proto (DSL) などの他のソリューションにもオープンであることに注意してください。

4

2 に答える 2

1

これは、c++03 で動作する Boost.Proto に基づくアプローチです。ドキュメントのこの例とは少し異なります。

次のように使用できます(残念ながら、他のソリューションほどきれいではありません):

// Initialize a map:
    Map json =
        map_list_of
            ("foo", "FOO")
            ("fuu", "FUU")
            ("bar", 
                    map_list_of
                        ("no", "abc")
                        ("yes", "ABC")
            )
            ("baa",
                    map_list_of
                        ("no", "xyz")
                        ("yes", "XYZ")
            )
        ;

Proto は次のようなツリーを構築します。

function(
    function(
        function(
            function(
                terminal(map_list_of_tag)
              , terminal(foo)
              , terminal(FOO)
            )
          , terminal(fuu)
          , terminal(FUU)
        )
      , terminal(bar)
      , function(
            function(
                terminal(map_list_of_tag)
              , terminal(no)
              , terminal(abc)
            )
          , terminal(yes)
          , terminal(ABC)
        )
    )
  , terminal(baa)
  , function(
        function(
            terminal(map_list_of_tag)
          , terminal(no)
          , terminal(xyz)
        )
      , terminal(yes)
      , terminal(XYZ)
    )
)

一致した式に応じて異なる変換を適用します。次の 4 つのケースがあります。

  • function(map_list_of,terminal,terminal): これは最も簡単なケースです。この例では、マッチング時に発生しますmap_list_of("foo","FOO")。単純にペア (キー、値) をマップに挿入し、参照を返します。

  • function(function,terminal,terminal): 1 番目 ( ) 以外の端子のペアが一致した場合に発生しますmap_list_of("foo","FOO")("fuu","FUU")。変換を最初の子に再帰的に適用して返されたマップにペア (キー、値) を挿入します。

  • function(map_list_of,terminal,function): これは、最初の括弧のペアにネストされたマップがある場合に発生します。ネストされたマップを作成し、キー ターミナルを使用して元のマップに挿入します。

  • function(function,terminal,function): これは、括弧で囲まれたグループをネストされたマップ ( ) と照合するときに発生しますmap_list_of("foo", "FOO")("fuu", "FUU")("bar", map_list_of("no", "abc")("yes", "ABC"))。ネストされたマップを作成し、barキーに挿入します。

完全なコード (Coliru で実行)

#include <map>
#include <string>
#include <iostream>
#include <boost/variant.hpp>
#include <boost/proto/core.hpp>
#include <boost/proto/transform.hpp>
#include <boost/type_traits/add_reference.hpp>
#include <boost/mpl/bool.hpp>
namespace proto = boost::proto;
using proto::_;
using boost::mpl::true_;
using boost::mpl::false_;

struct map_list_of_tag
{};


// A simple callable function object that inserts a
// (key,value) pair into a map.
struct insert
  : proto::callable
{
    template<typename Sig>
    struct result;

    template<typename This, typename Map, typename Key, typename Value>
    struct result<This(Map, Key, Value)>
      : boost::add_reference<Map>
    {};

    template<typename Map, typename Key, typename Value>
    Map &operator()(Map &map, Key const &key, Value const &value) const
    {
        map.insert(typename Map::value_type(key, value));
        return map;
    }
};

struct nest
  : proto::callable
{
    template<typename Sig>
    struct result;

    template<typename This, typename Map, typename Key, typename Value>
    struct result<This(Map, Key, Value)>
      : boost::add_reference<Map>
    {};

    template<typename Map, typename Key, typename Value>
    Map& operator()(Map& map, Key const &key, Value const &value) const
    {
        map[key]=Map();//assign a map to the variant at key
        map[key]=value;//assign a map_list_of_expr to a map
        return boost::get<Map&>(map[key]); //proto seems to need that this return value be a reference
    }
};

// Work-arounds for Microsoft Visual C++ 7.1
#if BOOST_WORKAROUND(BOOST_MSVC, == 1310)
#define MapListOf(x) proto::call<MapListOf(x)>
#define _value(x) call<proto::_value(x)>
#endif

// The grammar for valid map-list expressions, and a
// transform that populates the map.
struct MapListOf
  : proto::or_<
        proto::when<
            // map_list_of(a,b)
            proto::function<
                proto::terminal<map_list_of_tag>
              , proto::terminal<_>
              , proto::terminal<_>
            >
          , insert(
                proto::_data //the map you are assigning to
              , proto::_value(proto::_child1) //a char const [N] key
              , proto::_value(proto::_child2) //a char const [N] value
            )
        >
      , proto::when<
            // map_list_of(a,map)
            proto::function<
                proto::terminal<map_list_of_tag>
              , proto::terminal<_>
              , MapListOf
            >
          , insert(
                proto::_data //the map you are assigning to
              , proto::_value(proto::_child1)
              , nest(
                  proto::_data, //the map you are assigning to
                  proto::_value(proto::_child1), //a char const [N] key
                  proto::_child2 //a proto expression (map_list_of_expr) that represents a nested map
                )
            )
        >
      , proto::when<
            // map_list_of(a,b)(c,d)...
            proto::function<
                MapListOf
              , proto::terminal<_>
              , proto::terminal<_>
            >
          , insert(
                MapListOf(proto::_child0) //evaluates the transform recursively
              , proto::_value(proto::_child1) //a char const [N] key
              , proto::_value(proto::_child2) //a char const [N] value
            )
        >
      , proto::when<
            // map_list_of(a,b)(c,map)...
            proto::function<
                MapListOf
              , proto::terminal<_>
              , MapListOf
            >
          , insert(
                MapListOf(proto::_child0) //evaluates the transform recursively
              , proto::_value(proto::_child1) //a char const [N] key
              , nest(
                  proto::_data, //the map you are assigning to
                  proto::_value(proto::_child1), //a char const [N] key
                  proto::_child2 //a proto expression that represents a nested map
                )
            )
        >
    >
{};

#if BOOST_WORKAROUND(BOOST_MSVC, == 1310)
#undef MapListOf
#undef _value
#endif

template<typename Expr>
struct map_list_of_expr;

struct map_list_of_dom
  : proto::domain<proto::pod_generator<map_list_of_expr>, MapListOf>
{};

// An expression wrapper that provides a conversion to a
// map that uses the MapListOf
template<typename Expr>
struct map_list_of_expr
{
    BOOST_PROTO_BASIC_EXTENDS(Expr, map_list_of_expr, map_list_of_dom)
    BOOST_PROTO_EXTENDS_FUNCTION()

    template<typename Key, typename Value, typename Cmp, typename Al>
    operator std::map<Key, Value, Cmp, Al> () const
    {
        BOOST_MPL_ASSERT((proto::matches<Expr, MapListOf>));
        std::map<Key, Value, Cmp, Al> map;
        return MapListOf()(*this, 0, map);
    }
};

map_list_of_expr<proto::terminal<map_list_of_tag>::type> const map_list_of = {{{}}};

typedef boost::make_recursive_variant<std::string, std::map<std::string, boost::recursive_variant_> >::type Value;

typedef std::map<std::string, Value> Map;

struct printer : boost::static_visitor<void>
{
    printer(int indent) :indent(indent) {}

    void operator()(const std::string& val) const
    {
        std::cout << std::string(indent, ' ') << val << std::endl;
    }

    void operator()(const Map& val) const
    {
        for (Map::const_iterator it = val.begin(), end = val.end(); it != end; ++it)
        {
            std::cout << std::string(indent, ' ') << it->first << std::endl;
            boost::apply_visitor(printer(indent + 4), it->second);
            std::cout << std::string(indent, ' ') << std::endl;
        }
    }


    int indent;
};

void print(const Value& val)
{
    boost::apply_visitor(printer(0), val);
}

int main()
{

    // Initialize a map:
    Map json =
        map_list_of
            ("foo", "FOO")
            ("fuu", "FUU")
            ("bar", 
                    map_list_of
                        ("no", "abc")
                        ("yes", "ABC")
            )
            ("baa",
                    map_list_of
                        ("no", "xyz")
                        ("yes", "XYZ")
            )
        ;

    print(json);

    return 0;
}
于 2016-01-31T14:24:01.750 に答える