e.g.
#include <iostream>
using namespace std;
struct Point {
int x;
int y;
};
int main() {
Point p1 {1};
Point p2 {.y=2};
cout << p1.x << ", " << p1.y << endl;
cout << p2.x << ", " << p2.y << endl;
return 0;
}
https://ideone.com/DlJRfU
Is there any way to force the caller to initialize all struct members when using initializer lists? I want to ensure both x and y are set by the caller in this example.
I also want to allow designated initializers. Many of our structs are very long and that syntax adds much-needed clarity.
Something like what you want is possible in practice by making the aggregate meaninglessly templated:
template<class Bad>
struct PointImpl {
int x=Bad(),y=Bad();
};
using Point=PointImpl<void>;
void f() {
Point p0; // error
Point p1{1}; // error
Point p2{.y=2}; // error
Point p3{.x=1}; // error
Point p4{.x=1,.y=2}; // OK
}
I won’t say I morally agree with this sort of “defeat the client” approach, and it’s not even clear from the standard that default member initializers should work like default arguments this way ([temp.inst]/3, /11, and /13 don’t mention them at all), but implementations agree that they do.
You could add a 2-parameter constructor. That would force initializing with both parameters.
Point(int x, int y) : x(x), y(y) {}
Point() = default; // to maintain behaviour of default constructor
then
Point p1{1, 2}; // OK
Point p1 {1}; // error: no matching constructor for initialization of 'Point'
Point p2 {.y=2}; // error: no matching constructor for initialization of 'Point'
Note that this means Point is no longer an aggregate, which means you can no longer use designated initializers.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With