假设我有一个
boost::variant
定义为 boost::variant<Point, Line, Circle> shape
。现在,如果我创建一个 Point 类的对象 Point p
并将其存储为 shape = p
形状,我在这里所做的就是制作 p 的副本。我如何实际存储对 p 的引用,以便当我调用 boost::apply_visitior(visitor, shape)
时,访问者不仅会改变存储在变体中的 Point,还会改变 p
本身?
boost::variant<Point*, Line*, Circle*>
然后
shape = &p;
然后让你的访问者超载指针。
您不能在
variant
中存储引用(请参阅 std::variant
引用,它明确说明了这一点,但 boost::variant
非常相似),因为引用只是变量的另一个名称。 variant
是 union
的奇特实现。在这两种情况下,该值都存储在union
/variant
中。将您的对象放在那里可能需要付出副本的代价。对于小物体,我不会担心副本。如果您的对象很大并且需要避免复制,您可能需要考虑使用指针:
boost::variant<Point*, Line*, Circle*> shape;
shape s = &p;
使用指针,您甚至可能决定使用传统的多态方法而不是使用
variant
来实现此功能(定义一个抽象类
shape
, Point
、Line
和 Circle
继承自并使 s
成为父类型的指针:shape s = &p;
请注意,后者比使用
更容易出错。
将参考存储在boost::variant
中。
对于这样的变体,默认构造函数和复制运算符 可能会成为一个问题。但更重要的是:您必须关心设备的生命周期 自己存储引用(没有像shared_ptr那样的引用计数)。
using ShapeRef = boost::variant< Circle&, Square& >;
void resize_shape( ShapeRef _shape, double _val ) {
switch(_shape.which()) {
case 0:
boost::get<Circle&>(_shape).setradius( _val );
return;
case 1:
boost::get<Square&>(_shape).setsize( _val );
return;
default: throw Oops();
}
}
Circle c(10);
Square s(10);
resize_shape( c, 5 );
resize_shape( s, 5 );