web-dev-qa-db-ja.com

std :: visitの呼び出し内からstd :: variantの保留タイプを変更できますか

次のコードは未定義の振る舞いを呼び出しますか?

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を自由に実装できますか?

22
burnpanck

コードは問題ありません。

_std::visit_ の仕様には、訪問者が呼び出されたバリアントの代替を変更しないという要件はありません。唯一の要件は次のとおりです。

Requires:有効なパックごとにme(m)は有効な式でなければなりません。そのような式はすべて、同じタイプと値のカテゴリでなければなりません。そうしないと、プログラムの形式が正しくありません。

ビジターは各mの有効な式であり、常にvoidを返すため、要件を満たし、明確に定義された動作をします。

18
Barry