1) Почему?
Поскольку задействована функция - конструктор.Временный объект не связан напрямую с членом, а скорее связан с аргументом функции, чье время жизни продолжается до конца функции, что не выходит за пределы полного выражения, вызывающего функцию.
Он ничем не отличается от первого случая структур
Он отличается.В агрегатной инициализации нет конструктора.В этом случае компилятор знает время жизни элемента и знает, что элемент инициализируется временным.Применяется правило продления времени жизни.
, поэтому я считаю, что компилятор должен иметь возможность продлить время жизни всех временных объектов.
Рассмотрим следующий пример:
struct foo {};
struct bar {
bar(const foo& farg);
const foo& fmem;
};
bar b({});
Следует ли продлить срок службы временного на b
?Стандарт говорит, что это не так.Похоже, вы утверждаете, что так и должно быть.
Рассмотрите следующие возможные реализации конструктора:
bar::bar(const foo& farg) : fmem{farg} {} // 1
foo fanother;
bar::bar(const foo& farg) : fmem{fanother} {} // 2
Если реализация окажется равной 1, то вы догадались, расширение времени жизнинеобходимо.Если реализация равна 2, то мы излишне расширяем временное пространство, на которое больше не ссылаются.
Разработчики языка решили не расширять такое временное, вероятно, чтобы время жизни временных временных файлов не увеличивалось без необходимости.Как следствие, реализация 1 неверна, как и ваш пример CRTP.
Кратко: компилятор может только продлить время жизни временного объекта до времени жизни ссылки, к которой временный объект привязан напрямую.Компилятор не может знать, что будет сделано со ссылкой внутри функции.Он не может знать, что аргумент имеет отношение к члену.Они известны только тогда, когда конструктор скомпилирован, а не когда скомпилирован вызов конструктора.
2) Есть ли хороший способ преодолеть эту проблему?
Используйте либо int*
, либо std::reference_wrapper<int>
в качестве аргумента конструктора.Бывший более лаконичен, но последний обладает удобным свойством отсутствия нулевого представления.Это должно усложнить случайное связывание свисающей ссылки.В любом случае, тщательно документируйте, что указанный объект должен быть действительным при вызове Get
.