Попробуйте ответить, какие строчки некорректны с т.з. компилятора.
Ответ:
Строчка 1 некорректна. transform не может принимать функцию, которая возвращает ссылку
Строчка 2 корректна. and_then на это ограничение глубоко фиолетово.
Как бы оба участка кода идейно похожи. Оба пропускают через себя внутренний член объекта, оба для экономии места используют mem_fn.
И теперь вопрос на засыпку: какого лешего?
Здравствуйте, sergii.p, Вы писали:
SP>тут в последнее время любят поднимать тему нелогичности в языке. Я продолжу эту славную традицию
Строго говоря, тут нелогичность(по крайней мере, логичного обоснования пока нет) в библиотеке, а не в языке, но вопрос всё равно хороший.
У меня не получилось ни найти обсуждение/обоснование в интернете, ни придумать своё.
Мне кажется, ходом мысли для transform могло бы быть нечто вроде: если мы из функтора, переданного в transform, возвращаем ссылку, то автор кода может ожидать, что дальнейший chaining будет работать именно с этим объектом, а не копией, что не так в силу того, что optional<T&> запрещён.
С другой стороны, автор кода функтора для and_then, который возвращает ссылку на optional, также может возлагать тщётные надежды на отсутствие копии...
A type X is a valid contained type for optional if X is an lvalue reference type or ...
И вообще: [optional.optional.ref]]
Но ты наверное про старую версию языка пишешь, когда, действительно, специально было запрещено класть lvalue ref в optional.
SP>Как бы оба участка кода идейно похожи. Оба пропускают через себя внутренний член объекта, оба для экономии места используют mem_fn.
Они настолько же похожи, как указатель на массив похож на массив указателей. И правда — ведь и там, и там слова одинаковые! Эта аналогия, кстати, вполне уместна.
До вызова value_or в первой строке временный объект имеет тип optional<const double&>, а во второй строке — optional<double>.
Дальше, если в версии языка ссылки в optional класть запрещено, то будет ошибка компиляции.
Но сами методы optional тут в общем-то ни при чём: я и без transform/and_then всегда мог неаккуратно написать что-то вроде
Здравствуйте, watchmaker, Вы писали:
W>Но ты наверное про старую версию языка пишешь, когда, действительно, специально было запрещено класть lvalue ref в optional.
не знаю что за "старая" версия. В С++23 этого нет. Когда ждать 26-ой и будет ли оно там — отдельный вопрос. Всё-таки коммитет держал optional в калечном состоянии довольно долго, чтобы вот так сразу взять и исправить один из главных косяков cppreference настаивает что пока
The type must meet the requirements of Destructible (in particular, array and reference types are not allowed).
Здравствуйте, watchmaker, Вы писали:
W>Здравствуйте, sergii.p, Вы писали:
W>Но ты наверное про старую версию языка пишешь, когда, действительно, специально было запрещено класть lvalue ref в optional.
Я сначала обрадовался, а потом таки проверил, и у меня на актуальном компиляторе не получилось
Т.е. по факту пока таки нельзя.
Но у меня вопрос даже не про это, а про то, почему изначально результатом optional::transform сделали remove_cv_t, а не remove_cvref_t, ведь тогда бы transform позволял fn, возвращающий ссылку даже и на "старой версии языка".
Надо смотреть не столько на свежесть компилятора, сколько на версию __cpp_lib_optional.
_>Т.е. по факту пока таки нельзя.
Ага, поддержки в популярных реализациях STL пока ещё нет.
_>Но у меня вопрос даже не про это, а про то, почему изначально результатом optional::transform сделали remove_cv_t, а не remove_cvref_t
Кстати, изначально в proposal так и было. Потом при обсуждении дефект исправили.
_> ведь тогда бы transform позволял fn, возвращающий ссылку даже и на "старой версии языка".
А цель-то какая? Материализовать ссылки ценой ещё большего замедления optional? В нём и так уже не очень хорошая ситуация с лишними копированиями.
Согласен, что пока используешь простые типы, то невозможность написать o.transform(&Foo::val) сильно раздражала. Но для optional<Database> вред от незаметных копирований уже может перевешивать выигрыш от короткой записи.
Не знаю какой аргумент стал решающим, но итоговый вариант с сохранением ссылок мне нравится куда больше.
Здравствуйте, watchmaker, Вы писали:
W>А цель-то какая? Материализовать ссылки ценой ещё большего замедления optional? В нём и так уже не очень хорошая ситуация с лишними копированиями. <и далее>
Я же не оспариваю, мне интересно, каковы причины такого поведения, выбранного коммитетом. Я предполагал, что это защита от неожиданного копирования, но не нашёл тому подтверждения.
Верю на слово, что так и есть.