是否可以使用包含boost::变体的STL容器,并在变体类型本身中使用相同的容器类型
Is it possible to use an STL container containing a boost::variant and use the same container type in the variant type itself?
这似乎是不可能的,但我想我无论如何都会问。
我定义了一个boost::variant
,如下所示:
typedef boost::variant<double, int, std::string> ConfigVariant;
在我的代码后面,我定义了一个std::map
,如下所示:
std::map<std::string, ConfigVariant> my_map;
现在我希望能够在my_map
中具有std::map<std::string, ConfigVariant>
值。例如,我想这样做:
my_map[key1][key2] = "hello world";
我认为这是不可能的原因是,相应的变体定义看起来是这样的:
typedef boost::variant<double, int, std::string, std::map<std::string, ConfigVariant> ConfigVariant;
既然不可能做出这样的类型定义,有什么办法可以解决这个问题吗?
官方文档中有一节介绍递归变量类型。它解释了两种方法:使用boost::recursive_wrapper
和boost::make_recursive_variant
。我不确定是否有可能用recursive_wrapper
定义这种递归(我个人从未能够定义,但我远非专家)。与make_recursive_variant
相比,这真的很容易:你只需要用boost::recursive_variant_
替换你的递归变体类型,然后使用::type
来评估元函数并获得你想要的类型。
typedef boost::make_recursive_variant<
double,
int,
std::string,
//std::map<std::string,ConfigVariant>
std::map<std::string,boost::recursive_variant_>
>::type ConfigVariant;
在coliru 上运行
#include <iostream>
#include <string>
#include <map>
#include <boost/variant.hpp>
typedef boost::make_recursive_variant<double, int, std::string, std::map<std::string, boost::recursive_variant_> >::type ConfigVariant;
struct printer : boost::static_visitor<>
{
void operator()(int val) const
{
std::cout << val;
}
void operator()(double val) const
{
std::cout << val;
}
void operator()(const std::string& val) const
{
std::cout << val;
}
void operator()(const std::map<std::string,ConfigVariant>& val) const
{
std::cout << "map_of{ ";
for(std::map<std::string,ConfigVariant>::const_iterator it=val.begin(),end=val.end(); it!=end; ++it)
{
boost::apply_visitor(*this,it->second);
std::cout << " ";
}
std::cout << "}";
}
};
int main()
{
ConfigVariant intconf=1;
ConfigVariant doubleconf=1.2;
ConfigVariant stringconf="conf";
std::map<std::string, ConfigVariant> mapconf, mapconf2;
mapconf["int"]=intconf;
mapconf["string"]=stringconf;
mapconf2["map"]=mapconf;
mapconf2["double2"]=doubleconf;
ConfigVariant visitable=mapconf2;
boost::apply_visitor(printer(), visitable);
std::cout << std::endl;
}
这个问题实际上与boost::variant
无关;您只是要求使用标准容器制作一个n元树。
答案是否定的,因为标准容器要求使用完整的类型作为其模板参数。容器不能包含自己,因为正如您所观察到的,定义将是递归的。它的构造函数将预先假定它的构造函数已经存在。结果将是一个不完整的类型错误。
作为一种特殊情况,事实上std::vector
的实现通常允许这样做。在vector
的类定义完成之前,构造函数(以及任何其他需要完整元素类型的东西)实际上都不会实例化。所有标准容器都可以实现,使其以相同的方式工作。但这不是标准所要求的。
另请参阅是否可以用不完整的类型实例化标准容器模板;这也包含一个变通方法。为了将该解决方法应用于variant
,它本身需要一个完整的类型,我建议将不完整的类型封装在std::unique_ptr
中。
听起来你想要:
typedef boost::variant<double, int, std::string> ConfigVariant;
std::map<std::string, std::map<std::string, ConfigVariant> > my_map;
这将允许访问以下表单:
my_map["key 1"]["key 2"] = "hello world";
但不是形式:
my_map["key 1"] = "hello world";
使用boost::any将使其适用于您。我半小时前也写了这段代码,它也可以代替boost::variant
在您的情况下工作。它基本上只是一个荣耀的void*
指针,但带有类型检查断言。我想boost::any
也只是引擎盖下的一个空白,但我不确定我忘了我的代码并没有(故意)拥有数据的所有权——如果你想使用它,你必须修改它。这可能会很困难。boost:任何人都拥有所有权,所以这可能是更好的选择。
然后你的代码是:
typedef std::map<std::string, boost::any> ConfigMap;
或者使用智能指针:
struct Data;
typedef std::map<std::string, std::unique_ptr<Data> > ConfigMap;
struct Data
{
boost::variant<blah> value;
ConfigMap map;
};
把它想象成一个文件夹结构。文件夹包含文件,也可以包含文件夹。
这是在Ideone.com上编译的。不过,它最好封装在一个用户友好的类中。
- boost 是否有按特殊类型值编码状态"compact optional"?
- 像union_这样的 Boost.Geometry 操作如何处理浮点类型的基本不精确性?
- 来自 Android 应用程序内部的 boost 类型的 boost::wrapexcept<boost::system::system_error> 的未捕获异常
- 使用 Boost.Spirit 解析具有混合数据类型的 OBJ 文件?
- 使用自定义访问者时具有自定义类型的提升变体失败(源自 boost::static_visitor)
- 在其他容器中使用 boost::container::static_vector 时,GCC 编译错误"将'const s'绑定到类型's&'的引用丢弃限定符"
- Boost.Python :C++模板类型匹配的嵌套命名空间
- 我正在将一个 std::string 传递给一个 boost 函数,该函数对该类型进行常量引用,但该值发生了变化
- Boost.Hana:在 constexpr 上下文中将值元组转换为相应类型的元组
- 如何在Boost::program_options配置文件中为非字符串的自定义选项值类型处理空格
- 从具有部分专用化的boost:hana::set中提取类型失败
- boost odeint 中的受控误差步进器是否支持复杂的数据类型?
- boost::p rogram_options 验证每个参数而不是每个参数类型?
- 如何正确使用带有公共成员变量的类型 boost::可选?
- 无法解析类型 "boost::filesystem::path"
- 提升序列化提供未定义的类型'boost::STATIC_ASSERTION_FAILURE'
- C++ Boost - 未找到采用类型 'boost::filesystem::path' 的右操作数的运算符
- 无效使用不完整的类型boost function_traits
- C++,Linux:错误:请求从"boost::<void>unique_future"转换为非标量类型"boost::shared_future<void>"。 如何绕过它?
- BOOST/CSTDINT类型BOOST稀疏向量数组失败,为什么