Могу ли я изменить удерживаемый тип в std::variant из вызова std::visit

#c #c 17 #std-variant

#c #c 17 #std-variant

Вопрос:

Вызывает ли следующий код неопределенное поведение?

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

std::visit([amp;v](autoamp; 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
таким образом, чтобы описанное выше поведение было неопределенным?

Комментарии:

1. Вам нужны цитаты из стандарта для резервного копирования ответов, которые вы получаете?

2. Просмотрев [variant.visit] , я на 99% уверен, что этот код совместим и гарантированно не содержит UB, поскольку std::visit(vis, variant) должен быть эквивалентен vis(get</* active member */>(variant)) , но я недостаточно уверен в чтении стандарта, чтобы быть уверенным

3. @NathanOliver: Мне не нужны фактические цитаты из стандарта, если эксперты здесь могут договориться об ответе :-).

Ответ №1:

Код в порядке.

В спецификации std::visit нет требования, чтобы посетитель не менял альтернативу ни в одном из вариантов, по которым он вызывается. Единственным требованием является:

Требуется: Для каждого допустимого пакета m , e(m) должно быть допустимое выражение. Все такие выражения должны иметь один и тот же тип и категорию значений; в противном случае программа неправильно сформирована.

Ваш посетитель является допустимым выражением для каждого m и всегда возвращается void , поэтому он удовлетворяет требованиям и имеет четко определенное поведение.