With appropriate syntax, perhaps a user-defined constructor could be used in addition to designated/aggregate initialization? A constructor with a member initializer for each member followed by a body is similar to a designated initializer construction followed by a method call, perhaps that could be fused into a single statement? For example:

struct S {
    int a;
    S(int a) : a(a) { std::cout << "constructed an S instance: " << a << std::endl; };
};

int main() {
    S s(1);
};

could be equivalent to

struct S {
    int a;
    S() /* some tag that designates this constructor as "the aggregate/designated initializer constructor" */ { std::cout << "constructed an S instance: " << a << std::endl; };
};

int main() {
    S s = S{.a = 1};
};

In other words, adding the appropriate tag to a constructor means a) this class supports designated/aggregate initialization despite whatever other special member functions, and b) when designated/aggregate initialization is used, the body of this constructor is executed after all members are initialized (note: this would imply that the tagged constructor must have no arguments and no member initializers of its own, otherwise compile error).

Base class initialization in case of inheritance seems like it should work "fine", the existing mechanisms for designated/aggregate initializing base classes seems like they should follow naturally.

On Thu, Aug 18, 2022 at 2:42 PM Brian Bi via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
I don't think an attribute would be appropriate for this. With attributes a design principle is that the implementation should still be considered conforming if it ignores the attribute. Presumably you want to write portable code using your proposed feature, but if it were an attribute, then compilers could refuse to compile it by not supporting the attribute.

I am not aware of any proposals for this feature, but IMHO it is worth exploring. Scott Meyers explained that if, for example, you want to add logging to your class's destructor, then suddenly you're forced to explicitly default the move constructor, and as soon as you do that, your program will stop compiling if it employs aggregate initialization. It is not possible to perfectly emulate aggregate initialization using a user-written constructor, particularly now that we have designated initializers.  Having a way to explicitly opt in to aggregate initialization is the only way I can see to solve this problem.

On Thu, Aug 18, 2022 at 5:27 PM Ivan Matek via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
Often I encounter the following problem:
I am happily using the readability benefit of designated initializers in my struct.
Then I notice I must add a functionality that makes it a nonaggregate (for example deleting copy constructor to prevent accidental expensive copy), then all my nice initialization must go away and I am forced to write a spammy "forwarding" constructor (one that does nothing, just initializes all variables with mathiing arguments).

I am not sure what syntax would be best, maybe
[[agg_init]]
attribute?
--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals


--
Brian Bi
--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals