How can I create a required designator in C designated initializer aggregate initialization for structs? Or, put another way, how can I disable default initialization for a struct member?
What I'd like to be able to do is something like this.
struct A {
int x = required;
int y = 0;
};
A b{.x = 1, .y = 2}; // ok
A a{.x = 1}; // ok
A a{.y = 2}; // error
A a; // error
Context: https://en.cppreference.com/w/cpp/language/aggregate_initialization#Designated_initializers
CodePudding user response:
You can create multiple constructors for different scenarios like this:
struct A {
int x;
int y = 0;
A(int arg_x): x(arg_x){}
A(int arg_x, int arg_y): x(arg_x), y(arg_y){}
};
This will give the exact behaviour you want. Which might not exactly be what you are asking for but can be useful.
Or you can make x
a const
like this:
struct A {
const int x;
int y = 0;
};
With this, it looks more similar to what you have asked but now x must be uninitialized and you might not want a const variable in your struct.
CodePudding user response:
If you accept double braces for initialization, you can fully customize the designated initializers. You can even allow to exchange the order of .x
and .y
, if you want.
class A {
public: // allowed constructors
explicit A(A_x _x) : x(_x.x) {};
A(A_x _x, A_y _y) : x(_x.x), y(_y.y) {};
A(A_y _y, A_x _x) : x(_x.x), y(_y.y) {}; // include this line to enable initialization with .y as first and .x as second parameter
int x;
int y = 0;
private: // repeat constructors with each replaced with ambiguous one to force designated initializer
explicit A(A_i _i) = delete; // "same as" first constructor
A(A_x _x, A_i _i) = delete; // "same as" second constructor
A(A_i _i, A_y _y) = delete; // "same as" second constructor
A(A_i _i, A_x _x) = delete; // "same as" third constructor
A(A_y _y, A_i _i) = delete; // "same as" third constructor
struct A_x {
designated<int> x; // the name of the member variable is important
};
struct A_y {
designated<int> y; // the name of the member variable is important
};
struct A_i { // used to make A_x or A_y ambiguous
designated<int> i;
};
// can be moved outside of class
template<class C> // flexible for any member variable type
class designated { // require designated initializer
public:
designated(C c) : _c(c) {}; // implicitly converting
operator C() {return _c;}; // implicitly converting
private:
C _c;
};
};
int main() {
A a1{{.x = 1}, {.y = 2}}; // ok
A a2{{.y = 1}, {.x = 2}}; // ok (conditionally, see above how to change)
A a3{{.x = 1}}; // ok
A a4{{.y = 2}}; // error (no constructor could take source type)
A a5; // error (no default constructor)
A a6{}; // error (no default constructor)
A a7{{}, {.y = 2}}; // error (no constructor could take source type)
A a8{{0}, {.y = 2}}; // error (constructor ambiguous)
A a9{0, {.y = 2}}; // error (no constructor could take source type)
A a10{{.i = 4}, {.y = 3}}; // error (references a deleted function)
A a11{{A::A_x{0}}; // error (cannot access private struct)
A b1({.x = 1}, {.y = 2}); // ok
A b2({.y = 1}, {.x = 2}); // ok (conditionally, see above how to change)
A b3({.x = 1}); // ok
A b4({.y = 2}); // error (no constructor could take source type)
A b6(); // error (no default constructor)
A b7({}, {.y = 2}); // error (no constructor could take source type)
A b8({0}, {.y = 2}); // error (constructor ambiguous)
A b9(0, {.y = 2}); // error (no constructor could take source type)
A b10({.i = 4}, {.y = 3}); // error (references a deleted function)
A b11({A::A_x{0}); // error (cannot access private struct)
}