猿问

我可以列出-初始化一个只移动类型的向量吗?

我可以列出-初始化一个只移动类型的向量吗?

如果我通过GCC 4.7快照传递以下代码,它将尝试复制unique_ptrs进入向量。

#include <vector>#include <memory>int main() {
    using move_only = std::unique_ptr<int>;
    std::vector<move_only> v { move_only(), move_only(), move_only() };}

很明显这是行不通的,因为std::unique_ptr不可复制:

错误:使用已删除的函数‘std:UNIQUE_PTR<_TP,_dp>:UNIQUE_PTR(Const STD:UNIQUE_PTR<_TP,_DP>&)[WITTP=int;_dp=std:default_DELETE;STD:UNIQUE_PTR<_TP,_DP>=STD:UNIQUE_PTR]’

GCC试图从初始化程序列表复制指针是正确的吗?


神不在的星期二
浏览 436回答 3
3回答

天涯尽头无女友

简介<initializer_list>在18.9中,可以相当清楚地表明,初始化程序列表的元素总是通过Const-引用传递的。不幸的是,在当前语言的修订版中,在初始化程序列表元素中似乎没有任何使用移动语义的方法。具体而言,我们有:typedef const E& reference;typedef const E& const_reference;typedef const E* iterator;typedef const E* const_iterator;const E* begin() const noexcept; // first elementconst E* end() const noexcept; // one past the last element

慕的地10843

因为@Johannes似乎不想发布最好的解决方案作为一个答案,所以我就这么做。#include&nbsp;<iterator>#include&nbsp;<vector>#include&nbsp;<memory>int&nbsp;main(){ &nbsp;&nbsp;using&nbsp;move_only&nbsp;=&nbsp;std::unique_ptr<int>; &nbsp;&nbsp;move_only&nbsp;init[]&nbsp;=&nbsp;{&nbsp;move_only(),&nbsp;move_only(),&nbsp;move_only()&nbsp;}; &nbsp;&nbsp;std::vector<move_only>&nbsp;v{std::make_move_iterator(std::begin(init)), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::make_move_iterator(std::end(init))};}返回的迭代器std::make_move_iterator将在取消引用时移动指向元素。原文:我们要在这里利用一个小帮手类型:#include&nbsp;<utility>#include&nbsp;<type_traits>template<class&nbsp;T>struct&nbsp;rref_wrapper{&nbsp;//&nbsp;CAUTION&nbsp;-&nbsp;very&nbsp;volatile,&nbsp;use&nbsp;with&nbsp;care &nbsp;&nbsp;explicit&nbsp;rref_wrapper(T&&&nbsp;v) &nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;_val(std::move(v))&nbsp;{} &nbsp;&nbsp;explicit&nbsp;operator&nbsp;T()&nbsp;const{ &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;T{&nbsp;std::move(_val)&nbsp;}; &nbsp;&nbsp;}private: &nbsp;&nbsp;T&&&nbsp;_val;};//&nbsp;only&nbsp;usable&nbsp;on&nbsp;temporariestemplate<class&nbsp;T>typename&nbsp;std::enable_if< &nbsp;&nbsp;!std::is_lvalue_reference<T>::value, &nbsp;&nbsp;rref_wrapper<T>>::type&nbsp;rref(T&&&nbsp;v){ &nbsp;&nbsp;return&nbsp;rref_wrapper<T>(std::move(v));}//&nbsp;lvalue&nbsp;reference&nbsp;can&nbsp;go&nbsp;awaytemplate<class&nbsp;T>void&nbsp;rref(T&)&nbsp;=&nbsp;delete;遗憾的是,这里的直接代码无法工作:std::vector<move_only>&nbsp;v{&nbsp;rref(move_only()),&nbsp;rref(move_only()),&nbsp;rref(move_only())&nbsp;};由于标准没有定义如下的转换副本构造函数,无论出于什么原因://&nbsp;in&nbsp;class&nbsp;initializer_listtemplate<class&nbsp;U>initializer_list(initializer_list<U>&nbsp;const&&nbsp;other);这个initializer_list<rref_wrapper<move_only>>由大括号-init-列表创建({...})不会转换为initializer_list<move_only>认为vector<move_only>拿着。所以我们需要两步初始化:std::initializer_list<rref_wrapper<move_only>>&nbsp;il{&nbsp;rref(move_only()), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rref(move_only()), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rref(move_only())&nbsp;};std::vector<move_only>&nbsp;v(il.begin(),&nbsp;il.end());

隔江千里

如其他答案所述,std::initializer_list是按值保存对象,而不允许移出,因此这是不可能的。下面是一种可能的解决方法,使用函数调用,其中初始化器作为各种参数提供:#include&nbsp;<vector>#include&nbsp;<memory>struct&nbsp;Foo{ &nbsp;&nbsp;&nbsp;&nbsp;std::unique_ptr<int>&nbsp;u; &nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;x; &nbsp;&nbsp;&nbsp;&nbsp;Foo(int&nbsp;x&nbsp;=&nbsp;0):&nbsp;x(x)&nbsp;{}};template<typename&nbsp;V>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;recursion-ender &nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;multi_emplace(std::vector<V>&nbsp;&vec)&nbsp;{}template<typename&nbsp;V,&nbsp;typename&nbsp;T1,&nbsp;typename...&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;Types>void&nbsp;multi_emplace(std::vector<V>&nbsp;&vec,&nbsp;T1&&&nbsp;t1,&nbsp;Types&&...&nbsp;args){ &nbsp;&nbsp;&nbsp;&nbsp;vec.emplace_back(&nbsp;std::move(t1)&nbsp;); &nbsp;&nbsp;&nbsp;&nbsp;multi_emplace(vec,&nbsp;args...);}int&nbsp;main(){ &nbsp;&nbsp;&nbsp;&nbsp;std::vector<Foo>&nbsp;foos; &nbsp;&nbsp;&nbsp;&nbsp;multi_emplace(foos,&nbsp;1,&nbsp;2,&nbsp;3,&nbsp;4,&nbsp;5); &nbsp;&nbsp;&nbsp;&nbsp;multi_emplace(foos,&nbsp;Foo{},&nbsp;Foo{});}不幸的是multi_emplace(foos, {});失败,因为它无法推断{}因此,对于默认构造的对象,必须重复类名。(或使用)vector::resize)
随时随地看视频慕课网APP
我要回答