Ответ 1
Поведение GCC - ошибка, и исправлено на соединительной линии. Кланг верен. Это беспорядочный случай, потому что у вас есть смешанные категории значений для второго и третьего операндов условного оператора:
-
std::move(std::stringstream(""))
- это значение xvalue * типаstd::stringstream
; -
std::cin
- это значение типаstd::istream
.
Соответствующая стандартная цитата (§5.16 [expr.cond]/p3-6) находится в этом ответе. Это достаточно долго, что я действительно не хочу его копировать. Я просто расскажу, как он применяется к этому коду:
- Очевидно, что
std::istream
не может быть преобразован в соответствиеstd::stringstream
любым способом, независимо от категории значений; - Значение x типа
std::stringstream
не может быть преобразовано в тип "ссылка lvalue наstd::istream
" с учетом ограничения, что ссылка должна привязываться непосредственно к lvalue - здесь нет значения для ссылки для привязки; -
std::istream
является базовым классомstd::stringstream
, поэтому на 3-ю пулю p3 значение x типаstd::stringstream
может и будет преобразовано в значение prvalue, временное типаstd::istream
, путем инициализации копирования, которое заменяет исходный операнд для дальнейшего анализа. - Теперь второй операнд является prvalue типа
std::istream
, третий операнд является lvalue типаstd::istream
, у них разные категории значений, поэтому p4 не применяется. - Следовательно, результатом является prvalue per p5. Поскольку они имеют один и тот же тип, разрешение перегрузки, указанное в p5, не выполняется, и вы переходите к p6.
-
Применимая пуля в p6
Второй и третий операнды имеют один и тот же тип; результат этот тип. Если операнды имеют тип класса, результатом является значение prvalue временный тип результата, который инициализируется копированием из второй операнд или третий операнд в зависимости от значения первый операнд.
поэтому он копирует-инициализирует результат (который является временным значением prvalue) из либо преобразованного первого операнда, либо второго операнда (
std::cin
).
Следовательно, ошибки:
- Копирование-инициализация результата prvalue
std::istream
из lvalue (std::cin
) будет использовать конструктор копирования, а потоки не могут быть скопированы. - Копировать-инициализацию временного значения prvalue
std::istream
для второго операнда изstd::stringstream
xvalue - это перемещение, но конструктор перемещенияstd::istream
защищен.
* Для терминологии (lvalue, xvalue, prvalue и т.д.), см. Что такое rvalues, lvalues, xvalues, glvalues и prvalues?суб >