C++ 使用boostassign使用变量值初始化类似JSON的映射
我正在寻找一种存储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
{
"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;
}