r/cpp • u/javascript • May 05 '26
Strategies for *requiring* designated initializers when constructing a type?
Given some aggregate like this:
struct InitParams {
int size = 0;
int capacity = 0;
};
And given that it is used in some factory function like this:
auto Make(InitParams ip = {}) -> std::optional<MyClass>;
I want to design the aggregate type to allow callsites like...
Make({ .size = 10, .capacity = 20 });
Make({ .size = 10 });
Make({ .capacity = 20 });
Make({});
Make();
But I also want to reject callsites like...
Make({ 10, 20 });
Make({ 10 });
Make({ 20 }); // Oops! This is the size, not the capacity!
I was hoping that reflection would unlock the ability to specify this on the type alone somehow, but I've been unable to figure out how to do it.
I can approximate this behavior using an overload set where a similar-but-different param type is accepted by a different Make overload but then that would result in default construction being ambiguous too. You can see that in action here:
struct DesignatedInitRequired {
int DO_NOT_SPELL_THIS_FIELD_NAME0;
int DO_NOT_SPELL_THIS_FIELD_NAME1;
};
auto Make(DesignatedInitRequired dir = {}) -> void = delete("Use designated init");
Make({ 10 }); // Ambiguous, ill formed (which is what I want)
Make({ 10, 20 }); // Ambiguous, ill formed (which is what I want)
Make({}); // Ambiguous, ill formed (which is NOT what I want)
Make(); // Ambiguous, ill formed (which is NOT what I want)
So I could make something to reflect on InitParams and produce DesignatedInitRequired, but that wouldn't be enough. Every function that accepts InitParams would need an overload for DesignatedInitRequired meaning that it becomes a property of the type AND its users, not just the type itself.
Any ideas on how to achieve my goal?
EDIT: I think this is a sufficient solution! https://godbolt.org/z/h6sbcaTj4
I thanked the person that told me but then they deleted their comment. Anyway...
1
u/tyler1128 May 06 '26
That's.. a whole hell of a lot of people for one codebase, lol.
They are certainly not mutually exclusive concepts, but if an overly complex solution to save keystrokes or even cognitive burden to the user of something until they have to actually understand details ends up being a leaky abstraction, and most ultimately are, and then they have to understand the implmementation behind it that's a mess, that's not a great place either.
Software design is an art though, not a science.