13

You can declare a structure in C like so:

typedef struct MyStruct {
    const char *name;
    int (*func1)(void);
    int (*func2)(void);
    int (*func3)(void);
} MyStruct;

int test_func2(void) {
    return 0;
}

MyStruct test_struct = {
    .name   = "buffer",
    .func2  = test_func2,
};

This is quite handy for only defining particular members, all the other ones being set to 0/NULL.

Edit: in particular, this allows to not know the details of how MyStruct is defined, so it can change internally, adding new members etc.. without ever breaking code using this type.

This wouldn't compile with a C++ compiler however, getting error:

test.c:23: error: expected primary-expression before ‘.’ token
test.c:24: error: expected primary-expression before ‘.’ token

Is there an equivalent C++ declaration achieving the same?

Thanks.

Edit: @chris I can tell you don't understand :) And It's quite obvious that most other people commenting on what syntax I should have used, how the structure should have been defined etc.. have completely missed the point. This isn't about the correct way to define a structure, this snippet was only there to provide a context.

As for code equivalence, Say somewhere in your code you did:

MyStruct blah = { NULL, NULL, func2 };

Now MyStruct change its definition to be:

typedef struct MyStruct {
  const char *name;
  int (*func4)(void);
  int (*func1)(void);
  int (*func2)(void);
  int (*func3)(void);
} MyStruct;

Your code will still compile just fine, but has introduced a serious regression : instead of setting func2 like it used to, you would now initialise func1 member...

The question was about is there C++ designated initializers equivalent: there isn't. problem closed.

jyavenard
  • 2,142
  • 1
  • 26
  • 35
  • In C++, the whole `typedef struct A { ... } A;` thing is pointless. Use this: `struct A { ... };`. – chris Jun 02 '12 at 01:52
  • 4
    These are called [*designated initializers*](http://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html). They are valid in C99 but not C++. – Adam Rosenfield Jun 02 '12 at 01:55
  • @chris, great... so you're going to write struct A { ... } whenever you are going to use the definition externally? Now that will indeed be more efficient! not. – jyavenard Jun 02 '12 at 02:28
  • @jyavenard, I don't understand. Define the struct in a header and use it through objects like you are already. Nothing except the header should have anything to do with the definition of the struct itself. Other files would rather define the members of the struct. – chris Jun 02 '12 at 02:52
  • 1
    @jyavenard: In C++, if you declare the struct as `struct A {...} ` (or similarly `class A { ... } `), you can use them without the 'struct' or 'class'. Such as `void foo() { A a = ... } `. This is one of many major changes from C to C++ – Dave S Jun 02 '12 at 02:55
  • What do you mean by "Edit: in particular, this allows to not know the details of how MyStruct is defined". You can't use a designated initializer without a full definition of the type being initialized so I don't see how the presence or absence of designated initializers has any affect on the ability to use `MyStruct` as an incomplete type. – CB Bailey Jun 02 '12 at 08:30
  • You may want to take a look at the [Builder pattern](http://en.wikipedia.org/wiki/Builder_pattern). – fredoverflow Jun 02 '12 at 13:21
  • possible duplicate of [C++ Equivalent to Designated Initializers?](http://stackoverflow.com/questions/855996/c-equivalent-to-designated-initializers) – Jonathan Mee Mar 30 '15 at 02:47
  • Afaik, `g++` supports this as a GNU extension, so if you are not required to write portable code, you might just switch to the GNU C++ dialect. – cmaster - reinstate monica Sep 27 '16 at 11:32

4 Answers4

16

No, C++ does not support C99's designated initializers. If you want to set individual members by name, you'll need to do it via assignment, e.g.

MyStruct test_struct = MyStruct();
test_struct.name  = "buffer";
test_struct.func1 = test_func1;
James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • Unfortunately, that type of declaration isn't always possible. especially if test_truct is to be used elsewhere (e.g. in externally linked code)... Too bad there's no C++ equivalent. Thanks for answering – jyavenard Jun 02 '12 at 02:29
  • 5
    @jyavenard: If `test_struct` is a global variable, you may define a function that performs the initialization and returns the initialized object, then use that function to dynamically initialize the global variable (e.g. `MyStruct test_struct = ConstructTheStruct();`) – James McNellis Jun 02 '12 at 05:18
3

As K-ballo said, The code is equivalent to:

MyStruct test_struct = {
    "buffer",
    test_func1
};

But since you are using C++, you should considere writing and using constructors for MyStruct:

struct MyStruct {
    const char *name;
    int (*func1)(void);
    int (*func2)(void);
    int (*func3)(void);

    MyStruct(const char *n,
        int (*f1)(void) = NULL,
        int (*f2)(void) = NULL,
        int (*f3)(void) = NULL) : name(n), func1(f1), func2(f2), func3(f3) {}
};

Note that in C++ you do not need to typedef it to MyStruct, you can just use MyStruct (without the struct keyword) even without the typedef.

fbafelipe
  • 4,862
  • 2
  • 25
  • 40
  • 2
    and no it isn't equivalent... read the original question again... you have here filled the member func1 when you wanted func2 – jyavenard Jun 02 '12 at 02:05
  • 2
    while I'm using C++, the MyStruct code is actually defined in an external library, written in C. MyStruct happens to change from time to time, with new members being added, and not always at the end unfortunately. designated initializers allows to get around this problem. – jyavenard Jun 02 '12 at 02:08
  • 3
    @jyavenard: Then wrap your creation of these things in a factory function, who's interface you control. This is not a hard problem to solve. – Nicol Bolas Jun 02 '12 at 03:00
  • 1
    @jyavenard: So does setting each member individually. Sure, the syntactic sugar is nice, but it doesn't offer functionally that wouldn't exist otherwise. – Ed S. Jun 02 '12 at 03:17
  • @jyavenard Define macros, MyStruct_Initializer_n, where n is the number of arguments; e.g., `#define MyStruct_Initializer_3(func1,func2,func3) = { func1, func2, func3 }` ... the number and order of arguments for each macro will never change, so you don't risk introducing bugs when you add members, as long as you change all the macros to properly initialize new members that they don't take as arguments. – Jim Balter Jun 02 '12 at 03:22
  • @JimBalter You'd have to do number and position, to allow initialising e.g. `func1` and `func3` but not `func2` – Caleth Sep 08 '17 at 10:25
2

You can just use a lambda (since C++11). This will allow you to leave the declaration untouched, while easily initializing a global/constant instance of your structure:

struct Test
{
    int x;
    float y;
};

const Test test=[]{ Test t{}; t.x=5, t.y=3.3465; return t; }();

#include <iostream>
int main()
{
    std::cout << "test.x: " << test.x << ", test.y: " << test.y << "\n";
}

You can even wrap this into a macro, although in form below it'll only allow a fixed number of initializers:

// Macro to simplify it a bit
#define DECL_AND_INIT(Type,object,INIT1,INIT2) \
Type object=[]{ Type o{}; o.INIT1; o.INIT2; return o; }()
// Example usage
const DECL_AND_INIT(Test,test1,x=-7,y=-9.325e31);

Note that you still have to use value initialization like Test t{}; in the lambda — otherwise if you initialize not all members (e.g. due to addition of new ones), you'll end up copying uninitialized variables leading to UB.

Ruslan
  • 18,162
  • 8
  • 67
  • 136
1

The functional equivalence of this would be a constructor for your struct with an empty body:

#ifdef __cplusplus
MyStruct::MyStruct(char* N, int (*F)(void)) :
    name(N),
    func1(0),
    func2(0),
    func3(F) {
  // empty
}
#endif

(modulo some syntax errors, my C++ is a bit rusty.)

This is functionally equivalent, since it allows you to construct global objects even if they have const qualified fields, and any modern compiler should to the initialization of objects with static linkage at compile time.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177