Here is the code example where Test is a non-copyable and non-moveable class with some virtual members and a user-defined constructor, and B is a class that contains a raw (C-style) array of Test objects:
class Test
{
public:
Test() = delete;
Test(const Test&) = delete;
Test(Test&&) = delete;
Test& operator=(const Test&) = delete;
Test& operator=(Test&&) = delete;
Test(int a, int b) : a_(a), b_(b) {}
virtual ~Test() {}
int a_;
int b_;
};
//----------------
class B
{
public:
/*(1)*/ B() : test_{{1, 2}, {3, 4}} {} // Does not compile on GCC, but compiles on Clang and MSVC
private:
Test test_[2];
};
//----------------
int main()
{
B b;
/*(2)*/ Test test[2] = {{1, 2}, {3, 4}}; // Successfully compiles on GCC, Clang and MSVC
}
I want to initialize B's internal array test_ using the braced initialization syntax (line /*1*/), so that each of the two Test objects would be constructed in-place, without needing to create a temporary and then move it.
On Clang and MSVC, this code compiles without warnings.
But GCC's behavior confuses me: it fails to compile the line /*1*/, while successfully compiling the line /*2*/, where I am using the same syntax to initialize a local array. Yet for compiling the first line, it still requires the deleted move constructor of class Test.
The question is, why? Does the C++ standard clearly define whether these lines /*1*/ and /*2*/ should compile at all? If it does, which of the compilers is right from the standard's point of view? Can this inconsistent behavior be called a GCC bug, or do Clang and MSVC overlook some checks that they are supposed to perform?
I can understand that GCC might require a move constructor in order to create a temporary Test object from the inner braces ({1, 2}), and then move that object into an array. Hence the compilation error. But if that is so, why does it not fail on the line /*(2)*/ for the very same reason? This is the most confusing thing to me in this example.
By the way, here's an interesting observation: if I replace the definition of test_ with std::array<Test, 2> (instead of a "C-style" array), and replace the code in the constructor's initialization list with test_{{{1, 2}, {3, 4}}}, everything starts to compile successfully on all three mentioned compilers.
It is also unclear to me why does GCC not fail in this case on any line, while failing with a "raw" array.
Can anyone explain this as well?