I've been trying to produce a class with a member that is an std::array of a non-copyable type, that I need to initialize in the constructor. I had thought, referring to answers on this SO question, that the following would work:
#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;
}
And so it does, from GCC version 7.1.0 onwards with the C++17 or C++17(GNU) flags, according to Wandbox:
link to working compilation under GCC 7.1.0
However, though guaranteed copy elision support is listed for Clang++ from version 4 onwards, I can find no version that accepts the above code, up through the 9.0 or the current HEAD:
link to compiler error under Clang
The error that is yielded relates to the non-copy-constructibility of the array _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.
Is this a disagreement on the implementation of guaranteed copy elision between the compilers? Or, I've seen indications here on SO that guaranteed copy elision cannot be relied on and is entire optional for the compiler. Does that apply here, or only in cases where there is a copy constructor and GCE is not required for correct code?