【问题标题】:initializer_list<T> assignment operator requirement on Tinitializer_list<T> 对 T 的赋值运算符要求
【发布时间】:2014-10-27 20:52:37
【问题描述】:

我想知道 initializer_list&lt;T&gt; 是否要求 T 具有赋值运算符。以下

struct Foo
{
    Foo& operator=( const Foo& ) = delete;
};

std::vector<Foo> f = { Foo( ), Foo( ) };

在 clang 3.4.2 上编译,但在 Visual Studo 2013 上以 "error C2280: 'Foo &amp;Foo::operator =(const Foo &amp;)' : attempting to reference a deleted function" 失败。我假设 clang 在这里是正确的,但想检查 T 是否可以分配。

【问题讨论】:

    标签: c++ c++11 initializer-list


    【解决方案1】:

    std::initializer_list&lt;T&gt; 不需要以任何方式分配 T,因为复制 std::initializer_list 对象是浅层的 - 它不会复制底层数据。

    您收到错误是因为 MSVC 2013(及更低版本)不支持自动生成移动构造函数和移动赋值运算符。所以错误实际上来自std::vector 试图从初始化列表中复制,而不是从初始化列表本身。

    为什么会触发错误仍然是一个问题,因为采用std::initializer_liststd::vector 构造函数只需要类型为EmplaceConstructible 和可能的MoveInsertable,两者都不使用赋值。

    【讨论】:

    • 非常有趣,当您说“自动生成移动构造函数”时,您是指在 std::initializer_list 本身还是在 T 类型上。我试过 Fooas 遵循 struct Foo { Foo( ) { } Foo( const Foo& ) { } Foo( Foo&& ) { } Foo& operator=( const Foo& ) = delete; Foo& 运算符=( Foo&& ) = 删除; };
    • @goneskiing 我的意思是Foo 类型(实际上是任何用户定义的类类型)。当然,它也适用于std::initializer_list,但是作为库作者,他们可以通过明确定义移动操作来绕过它。不是他们需要;正如我所说,std::initializer_list 是一个浅包装器(内部可能只有两个指针)。
    • 因此,当我向 Foo 显式添加移动构造函数时,仍然会出现错误,我认为这意味着 VS 2013 initilizer_list 搞砸了。我确实尝试过 VS 14 CTP 3,它适用于原始 Foo
    • @goneskiing 或者他们的std::vector 搞砸了。您可以尝试只使用std::initializer_list,而无需将其传递给std 容器,和/或使用不同的容器(例如std::list,它永远不需要移动其项目)。
    • std::list 的工作方式与独立的 std::initializer_list 一样,因此您对 std::vector 的看法可能是正确的。谢谢,std::list 对我来说是一个很好的解决方法。
    猜你喜欢
    • 2017-09-15
    • 1970-01-01
    • 2023-02-02
    • 1970-01-01
    • 1970-01-01
    • 2011-11-09
    • 2011-04-23
    • 2015-01-11
    • 2011-07-21
    相关资源
    最近更新 更多