#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
, поэтому он удовлетворяет требованиям и имеет четко определенное поведение.