std::optional<int&> xx;
просто не компилируется для последнего моментального снимка gcc-7.0.0. Включает ли стандарт С++ 17 std::optional
для ссылок? А почему если нет? (Реализация с указателями в выделенной специализации, я думаю, не вызовет проблем.)
Почему GCC отклоняет std:: optional для ссылок?
Ответы (2)
Потому что optional
, стандартизированный в C++17, не разрешает ссылочные типы. Это было исключено конструкцией.
Этому есть две причины. Во-первых, структурно говоря, optional<T&>
эквивалентно T*
. У них могут быть разные интерфейсы, но они делают одно и то же.
Во-вторых, у комитета по стандартам фактически не было единого мнения о том, как именно должен вести себя optional<T&>
.
Рассмотрим следующее:
optional<T&> ot = ...;
T t = ...;
ot = t;
Что должна делать эта последняя строка? Берет ли он объект, на который ссылается ot
, и копирует-присваивает ему, например, *ot == t
? Или он должен перепривязать саму сохраненную ссылку, чтобы ot.get() == &t
? Хуже того, будет ли действовать по-разному в зависимости от того, был ли занят ot
до назначения?
Кто-то будет ожидать от него одного, а кто-то другого. Так что неважно, какую сторону вы выберете, кто-то будет сбит с толку.
Если бы вместо этого вы использовали T*
, было бы совершенно ясно, что происходит:
T* pt = ...;
T t = ...;
pt = t; //Compile error. Be more specific.
*pt = t; //Assign to pointed-to object.
pt = &t; //Change pointer.
*ot = t
. Кстати, у boost::optional
так и есть?
- person Vahagn; 02.11.2016
ot
не занят, я бы даже выбросил исключение, пока ot = t
.
- person Vahagn; 02.11.2016
*ot = t
. Если вы сделаете это, как бы вы перепривязали ссылку? Установите его в NULL, а затем установите его в новую ссылку? И как последний будет работать? Что делать, если у вас есть optional<optional<T&>>
? Будет ли выполнение ot = nullopt
отключать внешнюю или внутреннюю оболочку?
- person Nicol Bolas; 02.11.2016
o = t
, он перепривяжет и *o = t
назначит ссылку. У них также есть optional<bool>
путаница, и они решили, что работа с необязательным напрямую будет использовать необязательный выбор, а для работы со значением вы должны разыменовать. Ведь если сказать optional<int> o=1; o = nullopt
, то он тоже скомпилируется, несмотря на то, что nullopt
не конвертируется в int
.
- person Johannes Schaub - litb; 18.07.2017
optional<T&>
нет в C++17.
- person Nicol Bolas; 18.07.2017
optional<T&>
НЕ эквивалентно T*
. Согласно современным представлениям C++, если вы возвращаете T*
, вызывающая сторона может подумать, следует ли мне освободить указатель после его использования. Необработанный указатель может запутать, кто является владельцем объекта. Но если вы вернете optional<T&>
, вызывающая сторона не будет иметь дело с необязательным параметром, потому что он может быть либо пустым, либо ссылкой.
- person Alexander Chen; 02.06.2020
T*
всегда должно обозначать отсутствие права собственности. Если вы хотите представить передачу права собственности, в современном C++ это можно сделать с помощью какого-либо интеллектуального указателя. Таким образом, единственный раз, когда вызывающая сторона должна думать об этом, это если он имеет дело с кодом, написанным не в современном стиле C++.
- person Nicol Bolas; 02.06.2020
optional
? Для нессылочных типов то, что он делает, имеет смысл и хорошо понятно. Нет причин использовать только optional
для связи с/из функции.
- person Nicol Bolas; 29.04.2021
В [необязательно]:
Программа, которая требует создания экземпляра шаблона, необязательного для ссылочного типа, или, возможно, для типов с квалификацией cv
in_place_t
илиnullopt_t
, является неправильно сформированной.
std::optional<T&>
нет. На данный момент вам придется использовать std::optional<std::reference_wrapper<T>>
.
->
? std::reference_wrapper
, похоже, не реализует operator->
. Так что o->foo
не получится.
- person Johannes Schaub - litb; 18.07.2017
o->get().foo
, потому что ->
просто дает вам reference_wrapper
. Я очень надеюсь, что в конце концов мы получим optional<T&>
, который перепривязывается по заданию. Многие люди убедили меня, что это правильное поведение.
- person Barry; 18.07.2017
std::optional<T&>
в std::optional<std::reference_wrapper<T>>
, но автоматически разворачивает ссылку на operator->
и operator*
. operator=
перепривязывает ссылку.
- person monkey0506; 23.08.2019
optional
работает не так. В противном случае у вас не могло бы быть иoptional<non_default_constructible>
. Вы можете написать необязательный тип, поддерживающий ссылочные типы. Boost делает. Стандарт просто предпочитает этого не делать (из-заoperator=
). - person Barry   schedule 02.11.2016std::optional< std::reference_wrapper<int> >
:-D - person M.M   schedule 03.11.2016std::optoinal<std::variant<T&>>
։) - person Vahagn   schedule 08.11.2016