У меня есть структура с простым макетом, похожим на:
struct A
{
int a,b;
};
Я использовал равномерную инициализацию повсеместно для создания моей структуры, например:
A obj{2,3};
Позже я добавил конструктор в A. Теперь он выглядит так:
struct A
{
int a,b;
A(){}
};
Это нарушает использование равномерной инициализации. Есть ли простой способ сделать эту работу снова. Может быть, с помощью ключевого слова по умолчанию?
Я надеялся на что-то простое, чтобы соответствовать моей простой структуре.
Ваша исходная структура без конструкторов была агрегатного типа и поэтому позволяла вам использовать агрегатную инициализацию. Типы с предоставленными пользователем конструкторами не являются агрегатами, поэтому добавление конструктора нарушило использование инициализации агрегатов. Фактически, объявление этого конструктора делает его единственным конструктором и не позволяет инициализировать экземпляры этого типа любым другим способом, кроме как с этим конструктором.
Чтобы иметь такой конструктор, а также иметь возможность инициализировать экземпляры этого типа другими способами, вы должны объявить другие конструкторы с желаемым поведением. Если вы хотите иметь возможность инициализировать a и b, вы можете сделать что-то вроде следующего:
struct A
{
int a,b;
A(){}
A(int a_, int b_) : a(a_), b(b_) {}
};
Обратите внимание, что я ничего не упомянул о равномерной инициализации. Ничто из вышеперечисленного никоим образом не зависит от Uniform Initialization или C ++ 11. В чем заключается универсальная инициализация — это конкретный синтаксис, доступный для инициализации объектов.
В C ++ 03 агрегатная инициализация выглядела только так:
S s = {1, 2};
А в C ++ 03 использование конструктора выглядело так:
S s(1, 2);
В Uniform Initialization появилась возможность использовать один и тот же синтаксис для разных типов инициализации. То есть Единая инициализация может использоваться для агрегатной инициализации и инициализации через конструкторы.
Таким образом, в C ++ 11 вы можете использовать синтаксис:
A a{1, 2};
и это может быть агрегатная инициализация, если тип является агрегатом, или он может вызывать конструктор, если у типа есть конструкторы. Поскольку вы использовали Uniform Initialization для инициализации агрегата, чтобы продолжить использовать этот синтаксис с неагрегированным типом, вам просто нужно определить соответствующий конструктор.
Ваш простой конструктор вообще ничего не делает (даже не инициализирует a
а также b
). Если вы хотели их инициализировать, почему бы не сделать что-то вроде
struct A {
int a = 0, b = 0;
};
Сюда,
A x;
A y { 0 };
A z { 0, 0 };
Все работают и инициализируются a
а также b
до 0.
Если это не будет работать для вас, например, потому что у вас есть более сложный конструктор, тогда вы можете использовать делегирующие конструкторы следующим образом:
struct A {
int a, b;
A() : A(0, 0) { }
A(int x) : A(x, 0) { }
A(int x, int y) : a(x), b(y) { }
};
Или проще
struct A {
int a, b;
A(int x = 0, int y = 0) : a(x), b(y) { }
};
Все это будет работать с равномерной инициализацией.
В этом случае вы также должны объявить конструктор с двумя параметрами. Например
A( int a, int b ) : a( a ), b( b ) {}
Или вы можете объявить ваш конструктор по умолчанию как
A() = default;
без необходимости определять конструктор с двумя параметрами.
Если вы в C ++ 11, вы можете использовать std::initializer_list
, Вот основной пример:
struct A{
int a, b;
A(initializer_list<int> ilist){
if (ilist.size() == 2){
a = *ilist.begin();
b = *ilist.begin() + 1;
}else //throw an exception
}
};
Теперь ваша структура может быть инициализирована как A var = {1, 2}
На самом деле вы должны избегать типа {a, b} для агрегатов в первую очередь:
struct A
{
int a,b;
A() : a(0), b(0) {};
A(std::initializer_list<int> list) : a(*list.begin()), b(*(list.begin()+1)) {};
A(int x, int y) : a(0), b(0) { /* no arguments for a and b */ }
};
int main() {
int array[] = { 1, 2 };
A x{{1, 2}};
A y = {1, 2};
A z(1, 2);
}