Почему необработанный фигурный конструктор {} не возвращает значение?
Проблема в другом.
Проблема в том, что
data = { std::move(ds)..., {} };
вызовите "прямой конструктор" (конструктор (2) в этой странице ),
constexpr tuple( const Types&... args ); (2)
не «конвертирующий конструктор» (constructor (3))
template< class... UTypes >
constexpr tuple( UTypes&&... args ); (3)
что вы ожидаете.
Проблема в том, что "{}
" недостаточно для компилятора, чтобы вывести тип (последний тип для списка UTypes...
в конструкторе (3)), так что конструктор (3) исключается и Компилятор выбирает конструктор (2).
Конструктор Whit (2), "{}
" допустим для создания объекта последнего типа Types...
списка, потому что Types...
известен и не должен быть выведен.
Но constructor (2) - это конструктор копирования (с точки зрения Types...
кортежа), а не прямой конструктор как конструктор (3), поэтому первый вектор копируется, а не перемещается.
При звонке
все по-другому
data = { std::move(ds)..., std::move(std::vector<double>{}) };
или также
data = { std::move(ds)..., std::vector<double>{} };
, поскольку последний аргумент может быть явно выведен как std::vector<double>{} &&
, поэтому компилятор вызывает «конструктор преобразования» (constructor (3)) и перемещает содержимое первого вектора.
Не по теме: вместо использования std::vector<double>{}
, который работает только тогда, когда double
является последним из типов в Args...
, я предлагаю написать более общий код, используя std::tuple_element
.
Более того, я предлагаю SFINAE включить ваш конструктор только тогда, когда sizeof...(MoreArgs)+1u == sizeof...(Args)
.
Возможно также std::forward()
(включение идеальной пересылки) вместо std::move()
внутри лямбды.
Поэтому я предлагаю следующий конструктор
template <typename ... MoreArgs,
std::enable_if_t<sizeof...(MoreArgs)+1u == sizeof...(Args)> * = nullptr>
icecream(icecream<MoreArgs...>&& ice) {
std::apply(
[this](auto && ... ds) {
data = { std::forward<decltype(ds)>(ds)...,
std::tuple_element_t<sizeof...(Args)-1u,
decltype(data)>{} };
},
std::move(ice.data));
}