Array initialization with enum indices in C but not C++
February 15th, 2011 at 10:43 pmSuppose you have the following scenario: some function you’re writing needs a small lookup table keyed by enumeration values. It should preferably be static to avoid initializing it every time the function runs.
In C99, with support for named (a.k.a. "designated") initializers, this is possible in a very clean way:
#define ARRSIZE(arr) (sizeof(arr) / sizeof(arr[0]))
enum Fruit_t {
APPLES,
ORANGES,
STRAWBERRIES = 8
};
void foo()
{
static const int price_lookup[] = {
[APPLES] = 6,
[ORANGES] = 10,
[STRAWBERRIES] = 55
};
for (int i = 0; i < ARRSIZE(price_lookup); ++i) {
printf("[%d] = %d\n", i, price_lookup[i]);
}
}
The named initializer here is the funny syntax inside the braces assigned to price_lookup. Any constant expression can go inside the brackets, specifying which element of the array is assigned. As long as the compiler can resolve it at compile time, it’s fine. A similar syntax is supported for struct initialization.
Turns out that if you want to achieve the same effect in C++, you’re out of luck. Standard C++ does not support the named initializer construct – you’re stuck only with the old positional initialization of array elements.
So what do you do in C++? There are at least a couple of options, none of which is as clean as the one presented above, at least for our simple use-case.
One way is to make foo a method of some class (chances are, if you’re writing C++ code, that it already is) and have the lookup table a member initialized in the constructor. This isn’t very convenient for large classes, where you should be reluctant to pollute the members and constructors with helper data structures any of its methods needs.
Another way is to encapsulate the lookup table in a singleton object. Keep in mind, though, that a singleton in C++ is mostly just a prettified global variable, so when several such lookup tables in several functions are needed, things may become less clean than you’d want.
One may wonder why this feature is supported by C but not C++. Isn’t the latter a superset of the former? Well, no. While C++ indeed is almost a superset of the old C standard (ISO C, or C89/90), with the appearance of C99 the two languages grew further apart. Named initializers is one of the examples of C99 code that can’t be compiled in C++.
Related posts:

February 16th, 2011 at 01:18
Learned something new today. Didn’t know about C99′s named initializers. Never seemed to hold me back, but it’s good to know about it.
February 16th, 2011 at 13:19
In C++0x there is std::initializer_list. With some template metaprogramming magic I’m sure one could create a function like generates initializer_lists at compile time.
Say std::vector val = generate_initializer_list(coll, {APPLES, 6}, {ORANGES, 10}, {STRAWBERRIES, 55}));
Then again. I don’t miss this feature much. In C++ you first create an empty list, and then append values to it. I find it a bit clearer.
February 16th, 2011 at 13:25
Sorry, the “coll” there would be number of elements
February 16th, 2011 at 13:30
petke,
Thanks for the feedback. I’m not familiar with
std::initializer_list(or C++0x for that matter). Creating an empty list and appending values to it is not something done at compile-time, unfortunately.February 16th, 2011 at 16:43
std::initializer_list and & const_expr will likely become the C++ answer to this problem. Basically, std::initializer gets you “type object = { a, b, c};” style initialization. const_expr will get you limited compile time execution. For maps, you pass in key/value pairs, so this would work easily. You still won’t get designated initializers for things like vectors/arrays or class/structs without some kind of hack I don’t think.
February 16th, 2011 at 18:30
C++0x is like a whole new language. std::array is a fixed size collection, that gets its elements default constructed at compile time. In C++0x std::array supposed to works with std::initializer_list just like all other collections. So I guess that means it will have to initialize with std::initializer_list at compile time. I bet one could get the syntax you want (or something close to it), if one worked some metaprogramming magic one hid inside a convenient const_expr function.
Thanks
February 20th, 2011 at 01:05
C++0x allows this:
February 20th, 2011 at 07:47
Tim H,
Interesting, thanks. Can it be done at compile time, like the C version, though? I doubt it since
mapis a dynamic container the compiler doesn’t really know about, so this syntax is probably just syntactic sugar saving some constructor invocations.Again I must mention I’m unfortunately not familiar with C++0x at all.
February 21st, 2011 at 10:03
If you make that map static vaiable in function, it won’t be done in compile time, but it’ll be done only once during the execution. It’s not a big loss.
February 21st, 2011 at 12:38
@Aleksey,
True, and I mentioned something similar in the post itself – surely you can use a global static function, or a singleton for that. I was just lamenting the lack of possibility to avoid such external aids.