Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/145.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用boostassign使用变量值初始化类似JSON的映射_C++_Boost_C++03_Boost Variant_List Initialization - Fatal编程技术网

C++ 使用boostassign使用变量值初始化类似JSON的映射

C++ 使用boostassign使用变量值初始化类似JSON的映射,c++,boost,c++03,boost-variant,list-initialization,C++,Boost,C++03,Boost Variant,List Initialization,我正在寻找一种存储JSON结构的方法 { "foo" : "FOO" , "fuu" : "FUU" , "bar" : { "no" : "abc" , "yes" : "ABC" } , "baa" : { "no" : "xyz" , "yes" : "XYZ" } } 作为C++的映射,由 Boo:::赋值:::/Mult>像这样的 const

我正在寻找一种存储JSON结构的方法

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

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

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

作为C++的映射,由<代码> Boo:::赋值:::/Mult>像这样的

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" }
        }   
    };
const std::map=boost::assign::map\u列表
{
{“foo”,“foo”},
{“fuu”,“fuu”},
{“酒吧”,
{“否”,“abc”},
{“是”、“ABC”}
} ,
{“baa”,
{“否”,“xyz”},
{“是”,“XYZ”}
}   
};

其中一些键映射到字符串,而另一些键映射到子映射(hello变体)。请注意,我仅限于C++03,并对其他解决方案持开放态度,例如Boost Proto(DSL)

免责声明:我认为这可能是一种很酷的方法,但遗憾的是,我没有意识到(以
typedefs
和丑陋的
for
循环为见证,
BOOST\u METAPARSE\u STRING
需要c++11。所以这并不能解决问题中的问题

下面的方法使用的()应该从Boost 1.61开始提供。它使用一个宏(
JSON\u MAP\u ASSIGNER
),允许您直接使用问题中的原始JSON结构(请注意重复的括号)

这种方法有几个问题:

-它不能使用运行时字符串,它必须在编译时已知

-编译器可能会被足够大的json字符串阻塞


宏从“元组”创建一个字符串,解析该字符串,获得一个类型(
map\u assigner
),并实例化该类型。该实例将被指定给地图,并负责构建地图


完整代码

\define BOOST\u METAPARSE\u LIMIT\u STRING\u SIZE 128
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
名称空间分配辅助程序
{
使用名称空间boost::metaparse;
名称空间mpl=boost::mpl;
//map_assigner和pair assigner是实际分配给map的两个类
//开始分配
模板
结构映射赋值器
{
模板
结构分配
{
do_assign(std::map&val):map_(val){};
标准::地图和地图;
模板
void运算符()(对)常量
{
Pair::模板分配(映射);
}
};
//当一个map_assigner实例被分配给一个map时,这就完成了实际的工作
模板
运算符std::map()常量
{
//创建一个地图。。。
std::map m;
//…并分配每个对
mpl::for_each(do_assign(m));
返回m;
}
};
//如果是“正常”对(字符串,字符串)
模板
结构对赋值器
{
模板
静态无效分配(标准::映射和m)
{
m[mpl::c_str::type::value]=mpl::c_str::type::value;
}
};
//如果是一对,它的第二个参数是map
模板
结构对赋值器
{
模板
静态无效分配(标准::映射和m)
{
std::map nested_m=map_assigner();
m[mpl::c_str::type::value]=nested_m;
}
};
//最终转让人
//开始生成帮助程序
//这是用mpl::vector“调用”的(值可以是字符串或其他映射)
//并“创建”一对赋值器
模板
结构创建\对\赋值器:对\赋值器
{};
//这是用字符“调用”的
//并“创建”一个可以附加到
模板
struct create_string:string
{};
//这是用元素“调用”的
//并“创建”一个可以附加到
模板
结构创建向量:mpl::vector1
{};
//这是用vector/string和Elem/char“调用”的,并将后者附加到前者
模板
结构追加:mpl::推回
{};
//结束AST生成帮助程序
//开始代币
typedef标记>paren_open;
typedef标记>paren_close;
typedef标记>brake_open;
typedef标记>大括号关闭;
typedef标记>逗号;
typedef标记>冒号;
typedef lit_c<'“'>引号;
//结束标记
//开始规则
//这将解析并返回一个字母
键入一个单词字母;
//这将解析一个字母(可选后跟多个字母),并返回一个字符串
typedef foldl_start_与_解析器<
单词字母,
使改变
mpl::quote2>word;
//这将解析带引号的字符串并返回不带引号的字符串
typedef标记文字;
//这是一个递归规则,需要向前声明
结构体;
//值是字符串或映射
typedef一个值;
//它解析'string':'(string | map)`并返回pair_assigner或pair_assigner
typedef转换json_对;
//这将解析一对(可选后跟(“,”对)组)
//并返回一个map_赋值器
typedef变换<
foldl\u使用\u解析器启动\u<
最后一天,
使改变
mpl::quote2
>,
mpl::quote1>成对序列;
//这将解析“{pair\u sequence'}”,并返回pair\u sequence
struct json_body:
{};
//这将解析“'('json_body')”并返回json_body
//括号是一个工件,因为元组用于字符串化json文本以避免逗号问题
json的typedef middle_;
//结束规则
typedef构建解析器赋值器;
}
//创建映射赋值器并实例化它
#定义创建赋值器(文本)赋值器::赋值器::应用::类型()
#定义JSON映射赋值器(元组)创建赋值器(BOOST映射字符串化(元组))
typedef boost::make_recursive_variant::type Value;
类型定义s
    Map json = JSON_MAP_ASSIGNER((
    {
        "foo" : "FOO" ,
        "fuu" : "FUU" ,

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

        "baa" :
        {
            "no"  : "xyz" ,
            "yes" : "XYZ"   
        }
    }
    ));
#define BOOST_METAPARSE_LIMIT_STRING_SIZE 128

#include <iostream>
#include <string>
#include <map>

#include<boost/variant.hpp>

#include <boost/mpl/quote.hpp>
#include <boost/mpl/push_back.hpp>
#include <boost/mpl/string.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/for_each.hpp>

#include <boost/preprocessor/stringize.hpp>

#include <boost/metaparse/alphanum.hpp>
#include <boost/metaparse/string.hpp>
#include <boost/metaparse/lit_c.hpp>
#include <boost/metaparse/token.hpp>
#include <boost/metaparse/first_of.hpp>
#include <boost/metaparse/build_parser.hpp>
#include <boost/metaparse/entire_input.hpp>
#include <boost/metaparse/foldl_start_with_parser.hpp>
#include <boost/metaparse/transform.hpp>
#include <boost/metaparse/one_of.hpp>
#include <boost/metaparse/last_of.hpp>
#include <boost/metaparse/middle_of.hpp>
#include <boost/metaparse/sequence.hpp>




namespace assign_helper
{
    using namespace boost::metaparse;
    namespace mpl = boost::mpl;
    // map_assigner and pair assigner are the two classes that actually assign to the map
    //BEGIN ASSIGNERS
    template <typename PairSequence>
    struct map_assigner
    {
        template<class K, class V, class C, class A>
        struct do_assign
        {
            do_assign(std::map<K, V, C, A>& val) :map_(val) {};

            std::map<K, V, C, A>& map_;


            template <typename Pair>
            void operator()(Pair) const
            {
                Pair::template assign(map_);
            }
        };

        //This does the actual work when an instance of map_assigner is assigned to a map
        template<class K, class V, class C, class A>
        operator std::map<K, V, C, A>() const
        {
            //Creates a map...
            std::map<K, V, C, A> m;
            //...and assigns each of the pairs
            mpl::for_each<PairSequence>(do_assign<K, V, C, A>(m));

            return m;
        }
    };

    //if it's a "normal" pair (string,string)
    template <typename First, typename Second>
    struct pair_assigner
    {
        template <typename K, typename V, typename C, typename A>
        static void assign(std::map<K, V, C, A>& m)
        {
            m[mpl::c_str<First>::type::value] = mpl::c_str<Second>::type::value;
        }
    };

    //if it's a pair that has a map as its second param
    template <typename First, typename NestedSequence>
    struct pair_assigner<First, map_assigner<NestedSequence> >
    {
        template <typename K, typename V, typename C, typename A>
        static void assign(std::map<K, V, C, A>& m)
        {
            std::map<K, V, C, A> nested_m = map_assigner<NestedSequence>();
            m[mpl::c_str<First>::type::value] = nested_m;
        }
    };
    //END ASSIGNERS

    //BEGIN AST-BUILD HELPERS

    //This is "called" with a mpl::vector<string,char<':'>,value> (value can be either string or another map)
    //and "creates" a pair_assigner<string,value>
    template <typename Sequence>
    struct create_pair_assigner : pair_assigner<typename mpl::at_c<Sequence, 0>::type, typename mpl::at_c<Sequence, 2>::type>
    {};

    //This is "called" with a char<letter>
    //and "creates" a string<letter> which can be appended to
    template <typename Letter>
    struct create_string : string<Letter::value>
    {};

    //This is "called" with an Elem
    //and "creates" a vector<Elem> which can be appended to
    template <typename Elem>
    struct create_vector : mpl::vector1<Elem>
    {};

    //This is "called" with a vector/string and an Elem/char<letter> and appends the latter to the former
    template <typename State, typename Elem>
    struct append : mpl::push_back<State, Elem>
    {};
    //END AST BUILD HELPERS

    //BEGIN TOKENS
    typedef token < lit_c < '(' > > paren_open;
    typedef token < lit_c < ')' > > paren_close;
    typedef token < lit_c < '{' > > brace_open;
    typedef token < lit_c < '}' > > brace_close;
    typedef token < lit_c < ',' > > comma;
    typedef token < lit_c < ':' > > colon;
    typedef lit_c < '"' > quotation;
    //END TOKENS

    //BEGIN RULES
    //This parses and returns a letter
    typedef one_of<alphanum, lit_c<'_'>, lit_c<' '> > word_letter;

    //This parses a letter optionally followed by more and returns a string
    typedef foldl_start_with_parser<
        word_letter,
        transform<word_letter, mpl::quote1<create_string> >,
        mpl::quote2<append> > word;

    //This parses a quoted string and returns a string without quotes
    typedef token<middle_of<quotation, word, quotation> > literal;

    //This is a recursive rule and needs to be forward declared
    struct json_body;

    //A value is either a string or a map
    typedef one_of< literal, json_body > value;

    //This parses `string ':' (string|map)` and returns pair_assigner<string,string> or pair_assigner<string,map>
    typedef transform<sequence<literal, colon, value>, mpl::quote1<create_pair_assigner> > json_pair;

    //This parses a pair optionally followed by groups of (',' pair) 
    //and returns a map_assigner<vector<pair_assigner...> >
    typedef transform<
        foldl_start_with_parser<
        last_of<comma, json_pair>,
        transform<json_pair, mpl::quote1<create_vector> >,
        mpl::quote2<append>
        >,
        mpl::quote1<map_assigner> >pair_sequence;

    //This parses `'{' pair_sequence '}'` and returns pair_sequence
    struct json_body : middle_of<brace_open, pair_sequence, brace_close>
    {};

    //This parses `'(' json_body ')'` and returns json_body
    //the parentheses are an artifact due to the tuple used to stringize the json text to avoid problems with commas
    typedef middle_of<paren_open, json_body, paren_close> json;
    //END RULES

    typedef build_parser<entire_input<json> > assigner;
}

//Creates a map_assigner and instantiates it
#define CREATE_ASSIGNER(TEXT) assign_helper::assigner::apply<BOOST_METAPARSE_STRING(TEXT)>::type()


#define JSON_MAP_ASSIGNER(TUPLE) CREATE_ASSIGNER(BOOST_PP_STRINGIZE(TUPLE))




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()
{
    Map json = JSON_MAP_ASSIGNER((
    {
        "foo" : "FOO" ,
        "fuu" : "FUU" ,

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

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

    print(json);

}
// 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")
            )
        ;
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)
    )
)
#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;
}