Здравствуйте, Videoman, Вы писали:
V>Опять что-то перемудрили в стандарте или я неправильно понимаю ссылочные квалификаторы у методов класса?
Проблема связана с общими правилами продления жизни временных объектов константными ссылками. А не с квалификаторами методов класса, как с очень частным случаем этого правила.
V> В сухом остатке вот выжимка.
Всё ещё слишком много лишнего :)
Более минимизированный пример c падением во время работы:
https://godbolt.org/z/e1EnbbhvK
int main() {
const int& bad = std::min(5, 6);
printf("%d\n", bad); // UB
}
V> Стандарт позволяет вызвать метод у временного константного объекта.
И не только у метода — это опять же слишком частный случай.
Всегда и везде можно передавать временный объект по константной ссылке. Иначе бы такой код просто бы не компилировался:
const int good = std::min(5, 6);
Это дизайн языка, что по константной ссылке можно передать что угодно: число, строку или
*this.
V>Понятно, что можно добавить метод V>template<typename type_t>
V>nested_class get() const&& = delete;
V>
и всё будет работать как задумано.
Не нужно, пожалуйста, добавлять такие запрещения: от них вреда больше, чем пользы. Во-первых, они не все случаи ловят, во-вторых, они запрещают множество совершенно легитимных способов использовать классы:
printf("%d\n", holder_class().get<int>().get());
В твоём случае этот код не скомпилируется, хотя никакого UB нет.
Гораздо более практичный способ избежать подобных ошибок — использовать lifetimebound-атрибут, поддержка которого уже давно есть во многих компиляторах:
const nested_class& get() const& [[lifetimebound]];
После чего получать человекочитаемые сообщения:
error: temporary bound to local reference 'nested' will be destroyed at the end of the full-expression [-Werror,-Wdangling]
| const nested_class& nested = holder_class().get<int>();
| ^~~~~~~~~~~~~~
и при этом не получать ложных срабатываний при валидном использовании, в отличии от трюка с
&& = delete.
Демо:
https://godbolt.org/z/ea6ovve7v