c++arraysc++17copy-elisionuniform-initialization

Guaranteed copy elision for uniform braced array initialization - Shouldn't this be mandatory since C++17?


As far as I understand the new rules correctly

https://en.cppreference.com/w/cpp/language/copy_elision

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0135r0.html

This code should compile for C++17 standard conform compilers

struct NonTrivialClass
{
    ~NonTrivialClass( ){  }
};

class MainNonTrivialClass 
{
public:
  MainNonTrivialClass(int t) : m_simpleTypeMember(t) { }
 
  virtual void makeMySelfNonTrivial() {}

  MainNonTrivialClass( const MainNonTrivialClass& other) = delete;
  MainNonTrivialClass& operator=( const MainNonTrivialClass& other) = delete;
  MainNonTrivialClass(MainNonTrivialClass&& other) = delete;
  MainNonTrivialClass& operator=(MainNonTrivialClass&& other) = delete;
  
  NonTrivialClass m_nontrivialMember;
  int m_simpleTypeMember;
};

class ArrayContainer
{
public:
  ArrayContainer() : m_array{{1}, {2} } {}

private:
  MainNonTrivialClass m_array[2];
};


int main()
{
  ArrayContainer accContainer;
}

But gcc 9.1.0 with -std=c++17 -O2 -Wall -pedantic says (as totally expected for pre C++17)

main.cpp: In constructor 'ArrayContainer::ArrayContainer()':
main.cpp:25:39: error: use of deleted function 'MainNonTrivialClass::MainNonTrivialClass(MainNonTrivialClass&&)'
   25 |   ArrayContainer() : m_array{{1}, {2} } {}
      |                                       ^
main.cpp:15:3: note: declared here
   15 |   MainNonTrivialClass(MainNonTrivialClass&& other) = delete;

Array uniform initialization this way is defined as element-wise copy initialization(?) and should lead to copy elision so I do not really understand, what's actually going on here. The old pre C++17 rules seem to be applied here. A further curiosity is, that the same code compiles fine if I remove m_nontrivialMember from my MainNonTrivialClass but shouldn't it lead to the same compile error then always since the non-copy-elision case forces the existence of the according copy/move constructors always?


Solution

  • This should also work pre-C++17, where this syntax is direct-initialization. See How to initialize array of classes with deleted copy constructor (C++11) which refers to GCC bug 63707.