我可以在调用std::visit时更改std::variant中的持有类型吗?

24

以下代码是否会调用未定义行为?

std::variant<A,B> v = ...;

std::visit([&v](auto& e){
  if constexpr (std::is_same_v<std::remove_reference_t<decltype(e)>,A>)
    e.some_modifying_operation_on_A();
  else {
    int i = e.some_accessor_of_B();
    v = some_function_returning_A(i); 
  }
}, v);

具体来说,当变量不包含A时, 这段代码重新分配一个A,同时仍然保持对先前持有的类型为B的对象的引用。 但是,由于赋值后不再使用该引用, 我认为这段代码是正确的。 然而,标准库是否可以以一种使上述行为未定义的方式实现std::visit呢?


5
你需要引用标准来支持你得到的答案吗? - NathanOliver
1
从查看[variant.visit](http://eel.is/c++draft/variant.visit)来看,我99%确定此代码符合规范且保证不会有UB,因为`std :: visit(vis,variant)应等同于vis(get </ * active member * />(variant))`,但我对阅读标准的信心还不足以确定。 - Justin
@NathanOliver:只要这里的专家们能够达成一致意见,我就不需要标准文件中的实际引用:-)。 - burnpanck
1个回答

18

这段代码没有问题。

std::visit 的规范中并没有要求访问者不能更改任何被调用的变体的替代方案。唯一的要求是:

要求:对于每个有效的 pack me(m) 应该是有效表达式。所有这样的表达式应该具有相同的类型和值类别;否则,程序不合法。

你的访问者对于每个m都是一个有效的表达式,并始终返回void,因此它满足要求并具有良好定义的行为。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接