Home > Enterprise >  Required Designator in C 20
Required Designator in C 20

Time:10-05

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)
}
  • Related