LINUX.ORG.RU
ФорумTalks

Грустная история std::optional<T&>

 , ,


1

2

TLDR;

Коммитет настолько запутался в собственном языке и поленился выяснять, что к чему, что решил забанить эту конструкцию от греха подальше.

Фулл кулл стори:

Поскольку конструкция синтаксически валидная, но семантически не однозначная, решили забить на решение вопроса.

Вся драма в красках описана тут. «В красках» в прямом смысле слова - текст сопровождён картинками. Поскольку стори описана от сторонника одной из реализаций и члена коммитета С++, уровень драмы находится на надлежащем уровне.

Всем приятного чтения.

★★★★★

UB в string_view уже пофиксили?

RazrFalcon ★★★★★
()

члена коммитета С++

Текст не читал, можно конкретнее, в каком он там отделе и статусе? В https://thephd.github.io/about/ про это вообще ничего.

Есть https://thephd.github.io/portfolio/standard, где сказано что он пишет пропозалы. Но это ещё не делает членом комитета. Кто угодно может засылать пропозалы.

utf8nowhere ★★★
()
Последнее исправление: utf8nowhere (всего исправлений: 2)
Ответ на: комментарий от LamerOk

Выглядит прикольно, но довольно игрушечно для реального применения.

Надо получше посмотреть

yoghurt ★★★★★
()
Ответ на: комментарий от utf8nowhere

Но это ещё не делает членом комитета. Кто угодно может засылать пропозалы.

Почитай статью - он участвует во встречах и имеет доступ к «закрытой» рассылке.

LamerOk ★★★★★
() автор топика
Последнее исправление: LamerOk (всего исправлений: 1)

Грустная история

Почему грустная?

Поскольку конструкция синтаксически валидная, но семантически не однозначная, решили забить на решение вопроса.

А решение вообще есть?

По-моему, странно спорить как должен работать operator= для optional<T&>, если вообще непонятно, что вообще такое optional<T&>.

Если мы объявляем переменную (или non-static data member) со ссылочным типом, то имя этой переменной (мембера) становится именем объекта, определяемого при инициализации. Т.е.:

T v1 = initializer; // создаём и инициализируем объект типа T. v1 — имя этого объекта
T& v2 = v1; // не создаём и не инициализируем никаких новых объектов. v2 — имя для того же объекта, что именуется именем v1

Что такое optional<T> я понимаю. Это обозначает возможное отсутствие объекта типа T. А что значит optional<T&>???

utf8nowhere ★★★
()
Последнее исправление: utf8nowhere (всего исправлений: 2)

Коммитет настолько запутался в собственном языке

Вся суть крестокомбайна в одной фразе

upcFrost ★★★★★
()
Ответ на: комментарий от utf8nowhere

Юзкейс такой. На этапе кодоненерации объявляются ноды, каждая нода содержит данные и опциональную ссылку на следующую ноду. Ноды статически связываются друг с другом, образуя древовидную структуру. Копировать ноды нельзя.

seiken ★★★★★
()
Ответ на: комментарий от seiken

Мой поинт в том, что нет такой вещи (в смысле, материальной), как ссылка. Ссылку нельзя создать, уничтожить, скопировать, передать, вернуть и т.д. Когда я объявляю переменную как T v = init;, я говорю, что объект, именуемый v, создастся определением T v. Когда я объявляю переменную как T& v = init;, то я говорю, что объект, который будет именоваться v, будет определён инициализатором (либо это будет какой-то уже существующий объект, либо материализуется временный). Смысл в том, что T& v не «создаёт ссылку». Ссылок не существует в том смысле, в каком «существуют» объекты.

С такой точки зрения выражению «опциональная ссылка» нельзя дать какого-то осмысленного определения.

utf8nowhere ★★★
()
Ответ на: комментарий от utf8nowhere

Ссылку можно либо иметь, либо не иметь. optional< T&> это буквально аналог указателя, но с дополнительной семантикой поверх.

Проблемы неоднозначности вытекают из имплицитного разыменования ссылок в С++. Проблема неразрешима в текущем языке.

Siborgium ★★★★★
()
Ответ на: комментарий от Siborgium

Ссылку можно либо иметь, либо не иметь.

Это как?

Проблемы неоднозначности вытекают из имплицитного разыменования ссылок в С++.

Неоднозначности чего?

utf8nowhere ★★★
()
Последнее исправление: utf8nowhere (всего исправлений: 1)
Ответ на: комментарий от utf8nowhere

Это как?

Это как указатель. Он либо nullptr, либо указывает на что-то. Роль nullptr выполняет пустой optional. Проблема указателя в том, что легко получить ненулевой указатель, указывающий на невалидную память. С ссылкой, завернутой в optional, таких проблем нет, ссылка всегда валидна.

Неоднозначности чего?

Того, какая семантика должна быть у optional<T&>. Прочитайте статью, что ли.

Siborgium ★★★★★
()
Ответ на: комментарий от Siborgium

Это как указатель. Он либо nullptr, либо указывает на что-то.

При этом он всегда есть, а меняется его значение. Я спрашивал про то, как можно иметь или не иметь ссылку.

Того, какая семантика должна быть у optional<T&>. Прочитайте статью, что ли.

Читал статью. И ещё какую-то по ссылке оттуда. Выше описал своё мнение почему с operator= проблемы нет — потому что сама конструкция operator<T&> бессмысленна.

utf8nowhere ★★★
()
Последнее исправление: utf8nowhere (всего исправлений: 2)
Ответ на: комментарий от utf8nowhere

При этом он всегда есть, а меняется его значение.

как можно иметь или не иметь ссылку

Значение optional<T&> тоже всегда есть. Это либо ссылка, либо ничего. Приведу простой юзкейс для optional<T&> – его может возвращать поиск. Элемент либо найден, тогда optional содержит ссылку на него, либо ссылки нет, есть пустой optional.

Ваше мнение я прочитал, это чушь.

Мой поинт в том, что нет такой вещи (в смысле, материальной), как ссылка. Ссылку нельзя создать, уничтожить, скопировать, передать, вернуть и т.д.

Ссылка – указатель, наделенный семантикой валидности. Она вполне материальна. Все ссылки вы можете заменить указателями, но тогда вы потеряете эту самую семантику.

Ссылку можно передавать, копировать, возвращать. Ровно это и происходит, когда вы принимаете ее в качестве аргумента или возвращаете в качестве возвращаемого значения. Приведенный вами пример работает так из-за имплицитного взятия и разыменования ссылок в С++.

Siborgium ★★★★★
()
Ответ на: комментарий от Siborgium

Ваше мнение я прочитал, это чушь.

Ну-ну…

Ссылка – указатель, наделенный семантикой валидности.

Потому что ты так скозал?

Ссылку можно передавать, копировать, возвращать. Ровно это и происходит, когда вы принимаете ее в качестве аргумента или возвращаете в качестве возвращаемого значения.

Это неформальное (можно сказать: птушное) описание того, что происходит при вызове функции с ссылочным типом параметра или возвращаемого значения. С формальной точки зрения (стандарта), никаких передач или возвратов ссылок (в смысле их копирования) не происходит.

utf8nowhere ★★★
()
Последнее исправление: utf8nowhere (всего исправлений: 1)
Ответ на: комментарий от utf8nowhere

Потому что ты так скозал?

Да. Если вы скажете обратное, то разговор с вами можно будет заканчивать – я не вижу смысла спорить с человеком, не понимающим базовых вещей.

с формальной

стандарта

Какая разница, что говорит стандарт по этому поводу? Мы говорим о том, как это работает, а не о том, как это описано в стандарте.

никаких передач или возврата (…) не происходит

А, то есть, по вашему, ссылки самозарождаются на вызываемой стороне? Если в f(T&) передать lvalue, никаких «алиасов» там магически создано не будет. В функцию будет передана ссылка на lvalue, взятая имплицитно.

Siborgium ★★★★★
()
Ответ на: комментарий от Siborgium

Какая разница, что говорит стандарт по этому поводу?

Ну мы как бы делаем вид, что пытаемся определить в стандарте что такое optional<T&>.

А, то есть, по вашему, ссылки самозарождаются на вызываемой стороне?

Грустная история std::optional<T&> (комментарий):

нет такой вещи (в смысле, материальной), как ссылка. Ссылку нельзя создать, уничтожить, скопировать, передать, вернуть и т.д.

Если в f(T&) передать lvalue, никаких «алиасов» там магически создано не будет. В функцию будет передана ссылка на lvalue, взятая имплицитно.

lvalue вообще никуда передать нельзя. lvalue это вид выражений. «ссылка на lvalue» — это бессмысленный набор слов.

я не вижу смысла спорить с человеком, не понимающим базовых вещей.

Смешно.

utf8nowhere ★★★
()

вот до чего ссылки доводят. С указателями как-то проще

cvs-255 ★★★★★
()
Ответ на: комментарий от Siborgium

Мы говорим о том, как это работает, а не о том, как это описано в стандарте.

Пикантность ситуации в том, что в стандарте не описано как это работает. В отличие от указателей и любых других типов данных. И в общем случае конркетная реализация ссылок может быть совершенно любой.

LamerOk ★★★★★
() автор топика
Ответ на: комментарий от utf8nowhere

Все же, какой тип по хорошему возвращать get(«key») из hash map, если в языке есть optional? В этом случае не стоит им пользоваться? Пока что методы unordered_map без зазрений совести возвращают T& или стреляют ошибкой

vertexua ★★★★★
()
Последнее исправление: vertexua (всего исправлений: 2)

Вся драма из-за вот этого?

#include <optional>
#include <iostream>

int main (int, char*[]) {
	int x = 5;
	int y = 24;
	std::optional<int&> opt = x;

	opt = y;
	std::cout << "x is " << x << std::endl;
	std::cout << "y is " << y << std::endl;

	return 0;
}

Никто не может понять какая переменная все-таки окажется в opt.

Кажется магии слишком много, могли бы более явно сделать работу с этим optional

fn main() {
    
    let mut x = 10;
    let mut y = 20;
    
    let mut opt = Some(&mut x);
    
    println!("{:?}", opt);
    opt = Some(&mut y);
    println!("{:?}", opt);
    
    if let Some(y_ref) = opt {
        *y_ref = 30; 
    }
    
    println!("{:?}", y);
}

Если говорить все же в рамках C++ и если не указывать явно some, то я наверное за rebind вместо assign-through. Но все же я вот с ними

with a handful of folks saying “neither, everything should be explicit”

vertexua ★★★★★
()
Последнее исправление: vertexua (всего исправлений: 2)
Ответ на: комментарий от vertexua

Если говорить все же в рамках C++ и если не указывать явно some, то я наверное за rebind вместо assign-through.

а что делать, если я хочу именно assign-through? Ситуация вполне типичная для не const ссылок...

По идее, для rebind нужен другой «явный» синтаксис... Но тогда это будет уже не C++ :)

Sahas ★★★★☆
()
Ответ на: комментарий от vertexua

Все же, какой тип по хорошему возвращать get(«key») из hash map, если в языке есть optional? В этом случае не стоит им пользоваться?

Я бы возвращал просто указатель и проверял на нуль. Если кто-то, получая указатель, не может удержаться от арифметики с ним — я думаю, это ихние проблемы.

Пока что методы unordered_map без зазрений совести возвращают T& или стреляют ошибкой

Есть find, возвращающий итератор.

Не, конечно можно разрешить optional<T&> и приписать ему какую-нибудь семантику, но, ИМО, сравнивать/апеллировать при этом с/к «обычным(и)» ссылкам(и) идеологически некорректно.

utf8nowhere ★★★
()
Последнее исправление: utf8nowhere (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.