title: Has the C++17 extension to aggregate initialization made brace initialization dangerous?
body: <p>There seems to be a general consensus that <a href="https://stackoverflow.com/questions/18222926/why-is-list-initialization-using-curly-braces-better-than-the-alternatives">brace initialization should be preferred</a> over other forms of initialization, however since the introduction of the C++17 <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0017r1.html" rel="nofollow noreferrer">extension to aggregate initialization</a> there seems to be a risk of unintended conversions. Consider the following code:</p>
  
  <pre><code>struct B { int i; };
  struct D : B { char j; };
  struct E : B { float k; };
  
  void f( const D&amp; d )
  {
    E e1 = d;   // error C2440: 'initializing': cannot convert from 'D' to 'E'
    E e2( d );  // error C2440: 'initializing': cannot convert from 'D' to 'E'
    E e3{ d };  // OK in C++17 ???
  }
  
  struct F
  {
    F( D d ) : e{ d } {}  // OK in C++17 ???
    E e;
  };
  </code></pre>
  
  <p>In the code above <code>struct D</code> and <code>struct E</code> represent two completely unrelated types. So it is a surprise to me that as of C++17 you can "convert" from one type to another type without any warning if you use brace (aggregate) initialization. </p>
  
  <p>What would you recommend to avoid these types of accidental conversions? Or am I missing something?</p>
  
  <p>PS: The code above was tested in Clang, GCC and the latest VC++ - they are all the same.</p>
  
  <p>Update: In response to the answer from Nicol. Consider a more practical example:</p>
  
  <pre><code>struct point { int x; int y; };
  struct circle : point { int r; };
  struct rectangle : point { int sx; int sy; };
  
  void move( point&amp; p );
  
  void f( circle c )
  {
    move( c ); // OK, makes sense
    rectangle r1( c );  // Error, as it should be
    rectangle r2{ c };  // OK ???
  }
  </code></pre>
  
  <p>I can understand that you can view a <code>circle</code> as a <code>point</code>, because <code>circle</code> has <code>point</code> as base class, but the idea that you can silently convert from a circle to a rectangle, that to me is a problem.</p>
  
  <p>Update 2: Because my poor choice of class name seems to be clouding the issue for some.</p>
  
  <pre><code>struct shape { int x; int y; };
  struct circle : shape { int r; };
  struct rectangle : shape { int sx; int sy; };
  
  void move( shape&amp; p );
  
  void f( circle c )
  {
    move( c ); // OK, makes sense
    rectangle r1( c );  // Error, as it should be
    rectangle r2{ c };  // OK ???
  }
  </code></pre>