如何在添加自定义构造函数的同时保持聚合初始化?

ell*_*oor 32 c++ constructor aggregate-initialization

如果我没有在结构中定义构造函数,我可以通过选择某个值来初始化它,如下所示:

struct Foo {
    int x, y;
};

Foo foo = {.y = 1};
Run Code Online (Sandbox Code Playgroud)

但是如果我添加新的默认构造函数,那么我就会失去这个功能:

struct Bar {
    int x, y;
    Bar(int value) : x(value), y(value) {}
};

Bar bar1 = 1;
Bar bar2 = {.y = 2}; // error: a designator cannot be used with a non-aggregate type "Bar"
Run Code Online (Sandbox Code Playgroud)

是不是两种方法都可以呢?

我尝试添加默认构造函数Bar () {},但似乎也不起作用。

Sto*_*ica 35

你不能鱼与熊掌兼得。如果对象具有构造函数,则它不再是聚合,并且只能使用指定的初始值设定项来初始化聚合。您不能将构造函数用于具有聚合的任意初始化逻辑。

我们干杯了吗?不,因为有“命名构造函数”的习惯用法。它本质上只是一个静态成员函数,返回一个初始化的对象,并且能够执行一些逻辑。该习惯用法与聚合初始化兼容。

struct Foo {
    int x, y;
    static Foo filled_with(int value) {
        return {.x = value, .y = value};
    }
};

Foo foo = {.y = 1}; // Still an aggregate.
Foo foo2 = Foo::filled_with(2); // Custom logic
Run Code Online (Sandbox Code Playgroud)

这种方法甚至没有任何复制或移动,因为 C++17 消除了这些可能性。直接用静态成员所做的任何事情foo2进行初始化。


Gos*_*low 8

类似于 ellipticaldoor 所写的:

struct FooBase {
    int x = 0, y = 0;
};

struct Foo : FooBase {
    Foo(int x_) : FooBase{.x = x_} { }
    Foo(FooBase &&t) : FooBase{t} {}
};

Foo foo = {{.y = 1}};
Foo foo2{1};
Run Code Online (Sandbox Code Playgroud)