Похоже, существует общий консенсус в отношении того, что инициализация скобок должна быть предпочтительной по сравнению с другими формами инициализации, однако с тех пор, как введение расширения С++ 17 для агрегационной инициализации, похоже, представляет собой риск непреднамеренных преобразований. Рассмотрим следующий код:
struct B { int i; };
struct D : B { char j; };
struct E : B { float k; };
void f( const D& 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;
};
В коде выше struct D
и struct E
представляют два совершенно несвязанных типа. Поэтому для меня неожиданно, что с С++ 17 вы можете "конвертировать" из одного типа в другой без предупреждения, если вы используете инициализацию скобки (агрегата).
Что бы вы порекомендовали избежать этих случайных преобразований? Или я чего-то не хватает?
PS: приведенный выше код был протестирован в Clang, GCC и последнем VC++ - они все одинаковы.
Обновление: в ответ на ответ от Nicol. Рассмотрим более практичный пример:
struct point { int x; int y; };
struct circle : point { int r; };
struct rectangle : point { int sx; int sy; };
void move( point& p );
void f( circle c )
{
move( c ); // OK, makes sense
rectangle r1( c ); // Error, as it should be
rectangle r2{ c }; // OK ???
}
Я могу понять, что вы можете рассматривать circle
как point
, потому что circle
имеет point
качестве базового класса, но идея, что вы можете без проблем преобразовать из круга в прямоугольник, для меня является проблемой.
Обновление 2: Поскольку мой плохой выбор имени класса, по-видимому, помутняет проблему для некоторых.
struct shape { int x; int y; };
struct circle : shape { int r; };
struct rectangle : shape { int sx; int sy; };
void move( shape& p );
void f( circle c )
{
move( c ); // OK, makes sense
rectangle r1( c ); // Error, as it should be
rectangle r2{ c }; // OK ???
}