以下代码编译并执行"正确的事情":
#include <boost/variant.hpp>
#include <iostream>
int main()
{
int a = 10;
boost::variant<int&, float&> x = a;
a = 20;
std::cout << boost::get<int&>(x) << "\n";
return 0;
}
Run Code Online (Sandbox Code Playgroud)
boost :: variant如何存储引用?根据C++标准,如何存储引用完全取决于编译器.实际上,boost::variant甚至知道引用占用了多少字节?sizeof(T&) == sizeof(T),所以它不能使用sizeof()运算符.现在,我知道引用很可能是作为指针实现的,但是语言并不能保证.get<>当变体存储引用时,如何和访问工作的一个很好的解释获得额外的分数:)
我正在寻找C风格联盟的替代品.boost :: variant就是这样一个选择.std C++中有什么东西吗?
union {
int i;
double d;
}
Run Code Online (Sandbox Code Playgroud) 我正在使用boost变量来保存一些生成的类型,现在我的代码生成器创建了一个包含类型的头和一个能够保存它们的变体.在初始化时,我想迭代变体中的允许类型,而不是变体目前持有的类型.
我可以用变体做到这一点吗?
我想用一个boost.variant<T0,T1,T2>作为参数传递到模板"访问者"类,它会为游客提供运营商所要求的boost.variant游客机制,在这种情况下,所有返回void即
void operator()(T0 value);
void operator()(T1 value);
void operator()(T2 value);
Run Code Online (Sandbox Code Playgroud)
该模板还将为变体中的每个类型T0 ...具有相应的虚函数,该函数默认不执行任何操作.用户可以从模板类继承并仅重新定义他感兴趣的虚拟函数.这类似于众所周知的"模板方法"模式.我能够想出的唯一解决方案是将boost :: variant和关联的访问者包装在一个模板中,并通过typedef访问它们.这没关系,但感觉有点笨重.这是代码:
#include "boost/variant.hpp"
//create specializations of VariantWrapper for different numbers of variants -
//just show a template for a variant with three types here.
//variadic template parameter list would be even better!
template<typename T0, typename T1, typename T2>
struct VariantWrapper
{
//the type for the variant
typedef boost::variant<T0,T1,T2> VariantType;
//The visitor class for this variant
struct Visitor : public boost::static_visitor<>
{
void operator()(T0 value)
{ …Run Code Online (Sandbox Code Playgroud) typedef boost::variant<int, double> Type;
class Append: public boost::static_visitor<>
{
public:
void operator()(int)
{}
void operator()(double)
{}
};
Type type(1.2);
Visitor visitor;
boost::apply_visitor(visitor, type);
Run Code Online (Sandbox Code Playgroud)
是否可以更改访问者,以便它接收如下额外数据:
class Append: public boost::static_visitor<>
{
public:
void operator()(int, const std::string&)
{}
void operator()(double, const std::string&)
{}
};
Run Code Online (Sandbox Code Playgroud)
此字符串值在Append对象的生命周期内更改.在这种情况下,通过构造函数传递字符串不是一个选项.
我正在为verilog语言设计一个解析器,其中一个规则有25个组件,我需要一个大的boost :: variant来保存它:
typedef boost::variant<
shared_ptr<T_module_item__port_declaration>
, shared_ptr<T_module_item__generate_region>
, shared_ptr<T_module_item__specify_block>
, shared_ptr<T_module_item__parameter_declaration>
, shared_ptr<T_module_item__specparam_declaration>
, shared_ptr<T_module_item__net_declaration>
, shared_ptr<T_module_item__reg_declaration>
, shared_ptr<T_module_item__integer_declaration>
, shared_ptr<T_module_item__real_declaration>
, shared_ptr<T_module_item__time_declaration>
, shared_ptr<T_module_item__realtime_declaration>
, shared_ptr<T_module_item__event_declaration>
, shared_ptr<T_module_item__genvar_declaration>
, shared_ptr<T_module_item__task_declaration>
, shared_ptr<T_module_item__function_declaration>
, shared_ptr<T_module_item__local_parameter_declaration>
, shared_ptr<T_module_item__parameter_override>
, shared_ptr<T_module_item__continuous_assign>
, shared_ptr<T_module_item__gate_instantiation>
, shared_ptr<T_module_item__udp_instantiation>
, shared_ptr<T_module_item__module_instantiation>
, shared_ptr<T_module_item__initial_construct>
, shared_ptr<T_module_item__always_construct>
, shared_ptr<T_module_item__loop_generate_construct>
, shared_ptr<T_module_item__conditional_generate_construct>
> module_item ;
Run Code Online (Sandbox Code Playgroud)
但是g ++抱怨boost :: variant只能容纳不超过20种类型.
verilogast.h|1129 col 2| error: wrong number of template arguments (25, should be 20)
|| > module_item ;
|| ^ …Run Code Online (Sandbox Code Playgroud) 我想构造boost::variant包含默认构造值的s,使用类型索引指定 - 而不在类型索引上编写我自己的switch语句.
我认为这一定是可能的,不知何故,用MPL?
但要澄清一下,索引不是编译时常量表达式.
用例是我需要构造一个变体,稍后将替换为包含正确值的变量,但此时我只知道类型索引.把它想象成一个懒惰的反序列化问题.
我只是对boost::variant实施感到好奇.
这样工作吗?
两名成员:
apply_visitor():
有一个switch关于代表当前存储类型的数字的语句来调用正确的重载(在最坏的情况下,这将被编译为跳转表,因此需要恒定的时间).
我知道还有一些优化可以肯定boost::variant不需要动态分配内存,详见此处,但我想我得到了这些.
我很乐意得到并建议如何以"二维方式"处理boost :: variant.听起来很奇怪,但让我的代码说更多(希望如此):
我编写了一个名为Parameter的类:
template<typename PARAM_TYPE, typename DATA_TYPE=double>
class Parameter : public quantity<PARAM_TYPE, DATA_TYPE>
{
...
}
Run Code Online (Sandbox Code Playgroud)
上面定义的参数的示例用法:
Parameter<si::length, double> SampleParameter1;
Parameter<si::dimensionless, short> SampleParameter2;
Run Code Online (Sandbox Code Playgroud)
当我试图通过上面的例子解释时,我可以使用boost::units::si::???和不同的数据类型double, short, int等定义几个参数类型.
我的目标是构建一个std::map可以存储任何Parameter类型实例的容器(如上所示).
因此我宣布:
typedef boost::variant<Parameter<si::dimensionless, short>, Parameter<si::length, double> > SupportedParameterTypes;
std::map<int, SupportedParameterTypes> myMapStorage;
Run Code Online (Sandbox Code Playgroud)
这很好用,但有一个很大的缺点我想解决 - 我必须定义参数类型的每一个组合我想支持SupportedParameterTypes上面定义的类型.
我的想法是定义boost :: mpl :: vector,保留我想支持的所有参数类型:
typedef boost::mpl::vector<si::dimensionless, si::length> ParameterTypes;
Run Code Online (Sandbox Code Playgroud)
另一方面,支持所有可能的参数数据类型:
typedef boost::mpl::vector<short, int, float, double> ParameterDataTypes;
Run Code Online (Sandbox Code Playgroud)
我遇到了麻烦:
typedef typename boost::make_variant_over<ParameterTypes>::type ParameterTypeVariants;
typedef typename boost::make_variant_over<ParameterDataTypes>::type ParameterDataVariants;
typedef boost::variant<Parameter<ParameterTypeVariants, ParameterDataVariants> …Run Code Online (Sandbox Code Playgroud) 我有两个指针,只能设置其中一个,所以我正在考虑使用boost :: variant,比如说:boost::variant<shared_ptr<Type1> shared_ptr<Type2>>.类型1和类型2不同,但它们共享一些功能.例如,Thay都有这种方法IsUnique.
如果我有代码来检查初始化:
ASSERT(type1 != nullptr || type2 != nullptr);
ASSERT(type1 == nullptr || type2 == nullptr);
ASSERT(type1 == nullptr || type1->IsUnique());
ASSERT(type2 == nullptr || type2->IsUnique());
Run Code Online (Sandbox Code Playgroud)
我希望能够用尽可能接近的东西替换它:
ASSERT(variant != nullptr);
ASSERT(variant->IsUnique());
Run Code Online (Sandbox Code Playgroud)
但似乎我必须定义访问者,切换类型.
我是否会遗漏某些内容,是否有模板或某些内容可以让我将某些内容应用于当前类型的内容?它可能是c ++ 14.