具有boost :: any的cout地图 [英] cout map with boost::any

查看:59
本文介绍了具有boost :: any的cout地图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个可能嵌套的字典" std::map<std::string, boost::any>(或者,如果需要的话是std::any).现在,我想显示地图.由于boost::any显然不能很好地与<<配合使用,因此情况变得有些令人讨厌.到目前为止,我正在检查类型,将其强制转换并将其强制转换为cout:

I have a "dictionary" std::map<std::string, boost::any> (or std::any, if you want) that can possibly be nested. Now, I would like to display the map. Since boost::any obviously doesn't play nicely with <<, things are getting a little nasty. So far, I'm checking the type, cast it, and pipe the cast to cout:

for (const auto &p: map) {
  std::cout << std::string(indent + 2, ' ') << p.first << ": ";
  if (p.second.type() == typeid(int)) {
    std::cout << boost::any_cast<int>(p.second);
  } else if (p.second.type() == typeid(double)) {
    std::cout << boost::any_cast<double>(p.second);
  } else if (p.second.type() == typeid(std::string)) {
    std::cout << boost::any_cast<std::string>(p.second);
  } else if (p.second.type() == typeid(const char*)) {
    std::cout << boost::any_cast<const char*>(p.second);
  } else if (p.second.type() == typeid(std::map<std::string, boost::any>)) {
    show_map(
        boost::any_cast<std::map<std::string, boost::any>>(p.second),
        indent + 2
        );
  } else {
    std::cout << "[unhandled type]";
  }
  std::cout << std::endl;
}
std::cout << std::string(indent, ' ') << "}";

例如打印

{
  fruit: banana
  taste: {
    sweet: 1.0
    bitter: 0.1
  }
}

不幸的是,这几乎不可扩展.我必须为每种类型(例如,floatsize_t,...)添加另一个else if子句,这就是为什么我对该解决方案不满意的原因.

Unfortunately, this is hardly scalable. I'd have to add another else if clause for every type (e.g., float, size_t,...), which is why I'm not particularly happy with the solution.

是否可以将以上内容推广到更多类型?

Is there a way to generalize the above to more types?

推荐答案

可以减轻(但不能消除)痛苦的一件事是在使用静态多态性的同时将类型确定逻辑分解为一个支持函数(特别是模板) ),以便将操作应用于这些值...

One thing you can do to lessen (but not remove) the pain is to factor the type determination logic into one support function, while using static polymorphism (specifically templates) for the action to be applied to the values...

#include <iostream>
#include <boost/any.hpp>
#include <string>

struct Printer
{
    std::ostream& os_;

    template <typename T>
    void operator()(const T& t)
    {
        os_ << t;
    }
};

template <typename F>
void f_any(F& f, const boost::any& a)
{
    if (auto p = boost::any_cast<std::string>(&a)) f(*p);
    if (auto p = boost::any_cast<double>(&a))      f(*p);
    if (auto p = boost::any_cast<int>(&a))         f(*p);
    // whatever handling for unknown types...
}

int main()
{
    boost::any anys[] = { std::string("hi"), 3.14159, 27 };
    Printer printer{std::cout};
    for (const auto& a : anys)
    {
        f_any(printer, a);
        std::cout << '\n';
    }
}

(只需稍加努力,您就可以在可变参数模板参数包中对每种类型进行特定于类型的测试和分派,从而简化了代码并简化了维护列表的麻烦.或者,您可以只使用一个预处理程序宏以生成if-cast/dispatch语句....)

(With only a smidge more effort, you could have the type-specific test and dispatch done for each type in a variadic template parameter pack, simplifying that code and the hassle of maintaining the list. Or, you could just use a preprocessor macro to churn out the if-cast/dispatch statements....)

仍然-如果您知道类型集,则boost::variant更合适,并且已经支持类似的操作(请参见

Still - if you know the set of types, a boost::variant is more appropriate and already supports similar operations (see here).

另一种选择是在创建类型时记住"如何进行特定操作(例如打印):

Yet another option is to "memorise" how to do specific operations - such as printing - when you create your types:

#include <iostream>
#include <boost/any.hpp>
#include <string>
#include <functional>

struct Super_Any : boost::any
{
    template <typename T>
    Super_Any(const T& t)
      : boost::any(t),
        printer_([](std::ostream& os, const boost::any& a) { os << boost::any_cast<const T&>(a); })
    { }

    std::function<void(std::ostream&, const boost::any&)> printer_;
};

int main()
{
    Super_Any anys[] = { std::string("hi"), 3.14159, 27 };
    for (const auto& a : anys)
    {
        a.printer_(std::cout, a);
        std::cout << '\n';
    }
}

如果您有很多操作并希望减少内存使用量,则可以让模板化构造函数创建并存储(抽象基类)指针,该指针指向特定于静态类型的类,该类派生自抽象接口,其中包含您所执行的操作想要支持:这样,您只需为每个Super_Any对象添加一个指针.

If you have many operations and want to reduce memory usage, you can have the templated constructor create and store a (abstract-base-class) pointer to a static-type-specific class deriving from an abstract interface with the operations you want to support: that way you're only adding one pointer per Super_Any object.

这篇关于具有boost :: any的cout地图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆