初始化std :: map <...,boost :: any>中的子图

Nic*_*mer 3 c++ boost dictionary c++11

初始化a时std::map<std::string, boost::any>,该值boost::any确实可以采用任何类型的值,包括std::maps.然而,他们需要首先明确定义,例如,

#include <map>
#include <boost/any.hpp>
int main() {
  std::map<std::string, boost::any> a = {{"y", 2}};

  std::map<std::string, boost::any> any = {
    {"hh", 4},
    {"g", a}  // alright
  };
}
Run Code Online (Sandbox Code Playgroud)

隐含地尝试同样的事情,例如,

#include <map>
#include <boost/any.hpp>
int main() {
  std::map<std::string, boost::any> any = {
    {"hh", 4},
    {"g", {{"y", 2}}}  // mööp
  };
}
Run Code Online (Sandbox Code Playgroud)

导致编译错误

error: could not convert ‘{{"hh", 4}, {"g", {{"y", 2}}}}’ from ‘<brace-enclosed initializer list>’ to ‘std::map<std::__cxx11::basic_string<char>, boost::any>’
Run Code Online (Sandbox Code Playgroud)

出了什么问题?有没有办法让初始化适合一个语句?

ret*_*idi 9

好吧,编译器无法知道您的初始化列表最终应该成为什么类型.

给他一些帮助:

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

using namespace std;

int main() {
  using StringToAny = std::map<std::string, boost::any>;
  StringToAny any = {
    {"hh", 4},
    {"g", StringToAny{{"y", 2}}}  // jippie!
  };
}
Run Code Online (Sandbox Code Playgroud)

问题解决了.


Bri*_*ian 6

一般来说,你std::map<K, V>像这样初始化:

std::map<K, V> m = {{k1, v1}, {k2, v2}, ...};
Run Code Online (Sandbox Code Playgroud)

其中k1,k2,等等用于初始化的键,和v1,v2,等等用于初始化映射值.

现在我们可以看到,为了做你想做的事情,必须可以boost::any从你所处的位置初始化映射类型v2,即{{"y", 2}}.

这是不可能做到的.你做不到

boost::any a = {{"y", 2}};
Run Code Online (Sandbox Code Playgroud)

因此,您尝试初始化地图的方式也无法正常工作.

我看到这个问题是你今天早些时候发布的另一个问题的后续问题,而且你是来自Python背景.您的背景可能会让您相信它{{"y", 2}}本身就代表了一个地图,就像{'y': 2}Python中的字典文字一样.但是,在C++中并非如此; 相反{{"y", 2}},没有类型,甚至根本不是表达; 它是一个特殊的语法类别,称为braced-init-list.

一个支撑-初始化列表只能用于初始化.它用于确定用于初始化的构造函数,然后将其内容传递给所选的构造函数.尝试boost::any从像这样的braced-init-list初始化a 不起作用,因为编译器无法推断出你想先转换{{"y", 2}}成一个映射然后将该映射包装在其中boost::any.

解决方案是明确执行此转换.

std::map<std::string, boost::any> any = {
  {"hh", 4},
  {"g", std::map<std::string, boost::any>{{"y", 2}} }
};
Run Code Online (Sandbox Code Playgroud)