C++:嵌套映射

标签 c++ boost map nested boost-variant

定义如下:

struct nmap; struct nmap: map<string, boost::variant<string, nmap*>>{};

下面的最后一行不起作用:

nmap my_map; my_map["a"] = "b"; my_map["c"] = new nmap; my_map["c"]["d"] = "e";

我需要添加什么才能使其正常工作?

最佳答案

我建议要么找一个小巧的可读助手:

#include <boost/variant.hpp>
#include <map>

using std::map;

struct nmap;
struct nmap: map<std::string, boost::variant<std::string, nmap*>>
{
    typedef boost::variant<std::string, nmap*> Variant;
    typedef map<std::string, Variant> base;

    friend nmap&       as_map(Variant& v)       { return *boost::get<nmap*>(v); }
    friend nmap const& as_map(Variant const& v) { return *boost::get<nmap*>(v); }

    friend std::string&       as_string(Variant& v)       { return boost::get<std::string>(v); }
    friend std::string const& as_string(Variant const& v) { return boost::get<std::string>(v); }
};

int main()
{
    nmap my_map;
    my_map["a"] = "b";
    my_map["c"] =  new nmap;

    as_map(my_map["c"])["d"] = "e";
}

或者采用递归变体方式。让我素描:

递归变体树

这是 IMO 更优雅的:

#include <boost/variant.hpp>
#include <map>

using nmap  = boost::make_recursive_variant<std::string, std::map<std::string, boost::recursive_variant_> >::type;
using map_t = std::map<std::string, nmap>;

#include <iostream>
static std::ostream& operator<<(std::ostream& os, nmap const& map);

int main()
{
    nmap my_map = map_t
    {
        { "a", "b" },
        { "c", map_t
            {
                { "d", "e" },
                { "f", map_t
                    {
                        { "most nested", "leaf node" },
                        { "empty", map_t { } },
                    } },
            } },
        };

    std::cout << my_map;
}

乍一看这可能看起来更复杂,它实际上有许多重要的优点:

  • 不再继承不适合继承的类
  • 不再限制“根”对象/必须/是一个映射(它现在也可以是一个字符串,所以变体更一致地得到尊重)
  • 不再有内存泄漏 由于变体现在实际上负责分配实际的 nmap。在实例中,有开箱即用的完整值语义。
  • 允许对树进行惯用访问,不需要“ifs and buts dereferences”,例如考虑一下我们如何能够快速而肮脏地实现 operator<< :

    static std::ostream& operator<<(std::ostream& os, nmap const& map)
    {
        struct print : boost::static_visitor<void>
        {
            print(std::ostream& os, int indent = 0) : os(os), indent(indent) { }
    
            void operator()(map_t const& map) const {
                os << "{";
                for(auto& item : map)
                {
                    os << "\n";
                    do_indent();
                    os << "    " << item.first << ": ";
                    boost::apply_visitor(print(os, indent+4), item.second);
                }
                if (!map.empty()) { os << "\n"; do_indent(); };
                os << "}";
            }
    
            void operator()(std::string const& str) const {
                os << str;
            }
    
        private:
            std::ostream& os;
            void do_indent() const { for (int n = indent; n>0; --n) os << ' '; }
            int indent = 0;
        };
    
        boost::apply_visitor(print(os), map);
        return os;
    }
    

查看 Live On coliru

输出:

# g++ -std=c++11 -Wall -pedantic -Wextra main.cpp  && ./a.out

{
    a: b
    c: {
        d: e
        f: {
            empty: {}
            most nested: leaf node
        }
    }
}

关于C++:嵌套映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22274705/

相关文章:

c++ - 如何使用正则表达式解析 SIP 消息的多行 header ?

c++ - 尝试使用 operator[] 访问 std::map 元素时出现编译器错误

C++ 宏汇编错误

c++ - 多线程上的信号量和临界区问题

c++ - 使用 OpenMP 线程重新初始化 vector 是否更快?

c++ - 我可以使用 Boost.Asio 和 Boost.Beast 库发出 HTTPS 请求或 HTTP/2 请求吗?

c++ - 如何使 C++ 链接占用更少的内存

c++ - 标记化字符串,接受 CPP 中给定字符集之间的所有内容

android - 在 github 上共享我的代码时,如何隐藏我的 Google Maps API key ?

map - 如何使用 hadoop mapreduce 程序消除单个文件中的重复值