I have a struct with a simple layout, similar to:

struct A
{
   int a,b;
};

I have used uniform initialization all over the place to create my struct like:

A obj{2,3};

Later on, I have added a constructor to A. It now looks like:

struct A
{
  int a,b;
  A(){}
};

This breaks the use of uniform initialization. Is there a simple way to make this work again. Maybe by using the default keyword?

I was hoping for something simple, to match my simple struct.

有帮助吗?

解决方案 2

Your original struct without constructors was an aggregate type and therefore allowed you to use aggregate initialization. Types with user provided constructors are not aggregates, so adding the constructor broke your use of aggregate initialization. In fact declaring that constructor causes it to be the only constructor and prevents you from initializing instances of that type any way other than with that constructor.

In order to have such a constructor but also have the ability to initialize instances of that type in other ways, you have to declare other constructors with the desired behavior. If you want to be able to initialize a and b you can do something like the following:

struct A
{
  int a,b;
  A(){}
  A(int a_, int b_) : a(a_), b(b_) {} 
};

Note that I haven't mentioned anything about Uniform Initialization. None of the above is in any way dependent on Uniform Initialization or C++11. Where Uniform Initialization comes in is the specific syntax available to initialize objects.

In C++03 aggregate initialization looked only like:

S s = {1, 2};

And in C++03 using a constructor looked like:

S s(1, 2);

Uniform Initialization introduced the ability to use the same syntax for different types of initialization. I.e. Uniform Initialization can be used for aggregate initialization and initialization via constructors.

Thus in C++11 you can use the syntax:

A a{1, 2};

and this may be aggregate initialization if the type is an aggregate, or it may call a constructor if the type has constructors. Since you were using Uniform Initialization to initialize an aggregate, in order to continue using that syntax with a non-aggregate type you simply have to define an appropriate constructor.

其他提示

Your simple constructor does nothing at all (not even initialize a and b). If you meant to initialize them, why not do something like

struct A {
    int a = 0, b = 0;
};

That way,

A x;
A y { 0 };
A z { 0, 0 };

All work and initialize a and b to 0.

If that will not work for you because e.g. you have a more complicated constructor, then you can use delegating constructors like this:

struct A {
    int a, b;

    A() : A(0, 0) { }
    A(int x) : A(x, 0) { }
    A(int x, int y) : a(x), b(y) { }
};

Or more simply

struct A {
    int a, b;

    A(int x = 0, int y = 0) : a(x), b(y) { }
};

All these will work with uniform initialization.

In this case You should also declare a constructor with two parameters. For example

A( int a, int b ) : a( a ), b( b ) {}

Or you could declare your default constructor as

A() = default; 

without necessary to define the constructor with two parameters.

If you're in C++11, you can use std::initializer_list. Here is a basic example:

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
    }
};

Now your struct can be initialized like A var = {1, 2}

Actually you should avoid type{a, b} on aggregates in the first place:

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);
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top