Ваш код должен работать нормально, потому что в return return :
(акцент мой)
(начиная с C ++ 11)
Если выражение является выражением lvalue и условиями для копирования
соблюдаются или будут соблюдены, за исключением того, что
параметр функции, затем разрешение перегрузки, чтобы выбрать конструктор
Для использования для инициализации возвращаемое значение выполняется дважды:
сначала, как если бы выражение было rvalue выражением (таким образом, оно может выбрать
конструктор перемещения или конструктор копирования со ссылкой на const),
и если нет подходящего преобразования, разрешение перегрузки
выполняется во второй раз, с выражением lvalue (так что он может выбрать
конструктор копирования, ссылающийся на неконстантный).
Приведенное выше правило применяется, даже если тип возвращаемого значения функции отличается
из типа выражения (для копирования требуется тот же тип)
Это означает, что даже result
является lvalue, сначала оно будет рассматриваться как r-значение, затем будет выбран следующий конструктор , который может преобразовать std::unique_ptr<Stats>
в std::unique_ptr<const Stats>
.
template< class U, class E >
unique_ptr( unique_ptr<U, E>&& u ) noexcept;
Кажется, что gcc4.9.2 не ведет себя таким образом (т.е. сначала обрабатывает выражение как выражение rvalue); gcc 9 просто отлично работает.
Как прокомментировал @ RichardHodges , вы можете использовать std::move
в качестве обходного пути .