gpt4 book ai didi

c++ - G++ 7.1.0 及更高版本支持此构造函数中的保证复制省略,但 Clang++ 4.0 及更高版本不支持

转载 作者:行者123 更新时间:2023-11-30 01:33:32 24 4
gpt4 key购买 nike

我一直在尝试生成一个类,其成员是不可复制类型的 std::array,我需要在构造函数中对其进行初始化。我曾想过,引用this SO question上的答案, 以下内容将起作用:

#include <array>
#include <utility>

class Foo {
public:
Foo() {}
Foo(const Foo& rhs) = delete;
Foo(Foo&& rhs) = delete;
};

template<size_t BufferSize>
class FooBuffer {
public:

template<size_t... Is>
FooBuffer(std::index_sequence<Is...>)
: _buffer({{(static_cast<void>(Is), Foo{})...}})
{
}

FooBuffer() : FooBuffer(std::make_index_sequence<BufferSize>{}) {}

private:

std::array<Foo,BufferSize> _buffer;

};

using namespace std;
int main(int, char **) {
FooBuffer<10> foo;
}

根据 Wandbox 的说法,从带有 C++17 或 C++17(GNU) 标志的 GCC 版本 7.1.0 开始,它确实如此:

link to working compilation under GCC 7.1.0

但是,尽管从版本 4 开始为 Clang++ 列出了保证复制省略支持,但我找不到接受上述代码的版本,直到 9.0 或当前的 HEAD:

link to compiler error under Clang

产生的错误与数组 _buffer 的不可复制构造性有关:

prog.cc:18:5: error: call to implicitly-deleted copy constructor of 'std::array<Foo, 10UL>'
: _buffer({{(static_cast<void>(Is), Foo{})...}})
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
prog.cc:22:16: note: in instantiation of function template specialization 'FooBuffer<10>::FooBuffer<0, 1, 2, 3, 4, 5, 6, 7, 8, 9>' requested here
FooBuffer() : FooBuffer(std::make_index_sequence<BufferSize>{}) {}
^
prog.cc:32:16: note: in instantiation of member function 'FooBuffer<10>::FooBuffer' requested here
FooBuffer<10> foo;
^
/opt/wandbox/clang-head/include/c++/v1/array:143:9: note: copy constructor of 'array<Foo, 10>' is implicitly deleted because field '__elems_' has a deleted copy constructor
_Tp __elems_[_Size];
^
prog.cc:8:2: note: 'Foo' has been explicitly marked deleted here
Foo(const Foo& rhs) = delete;
^
1 error generated.

这是编译器之间对保证复制省略的实现的分歧吗?或者,我在这里看到关于 SO 的迹象表明不能依赖保证的复制省略,并且对于编译器来说是完全可选的。这适用于此处,还是仅适用于存在复制构造函数且正确代码不需要 GCE 的情况?

最佳答案

当你做的时候

_buffer({{(static_cast<void>(Is), Foo{})...}})

{(static_cast<void>(Is), Foo{})...} part 为一个对象构建一个 braced-init-list。外层{}是用于创建 braced-init-list 引用的对象的大括号。由于这些列表都没有类型,因此编译器必须枚举 _buffer 的构造函数找出要调用的内容。当编译器执行此操作时,发现的只是隐式生成的复制和移动构造函数。自 Foo不能复制/移动那些被隐式删除,这意味着没有可以调用的构造函数。

如果你切换到

_buffer{(static_cast<void>(Is), Foo{})...}

然后你就可以直接初始化_buffer了自 Foo{} 以来,这保证有效纯右值不会被复制,而是直接在适当的位置创建。

你也可以切换到使用

_buffer(std::array<Foo,BufferSize>{{(static_cast<void>(Is), Foo{})...}})

这会起作用,因为现在您确实有一个类型为 std::array<Foo,BufferSize> 的纯右值而不是复制它直接在 _buffer 中初始化.


相关标准可在 [dcl.init]/17 中找到

  • If the initializer expression is a prvalue and the cv-unqualified version of the source type is the same class as the class of the destination, the initializer expression is used to initialize the destination object.

强调我的

由于 braced-init-list 没有类型,它不符合上述要点,因此不能保证复制省略。

关于c++ - G++ 7.1.0 及更高版本支持此构造函数中的保证复制省略,但 Clang++ 4.0 及更高版本不支持,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58378621/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com