I have the following code in C++ (C++11 is available)
typedef enum
{
APPLE,
ORANGE,
LAST,
} fruits_t;
template <typename T, size_t size> char (&ArraySizeHelper( T (&)[size]))[size];
#define arraysize(pArray) sizeof(ArraySizeHelper(pArray))
static const char *LOOKUP_TABLE[]
{
"apple", // APPLE
"orange", // ORANGE
};
// Fail the compilation if the lookup table is missing anything
static_assert(arraysize(LOOKUP_TABLE) == LAST, "Update the lookup table");
I want to be able to change the order in the enumeration without changing the initialisation list in the LOOKUP_TABLE.
I have read this Initialization of a normal array with one default value and the template is almost what I need, but not quite. I struggled with metaprogramming for half a day and still can not figure out how to do it.
The actual enumeration in the code starts from zero and contains 20-30 entries. I have considered a hash table - the hash function is trivial, but the problem of initialization remains. I have many - 5+ - lookup tables like this in the code. Is it worth the struggle?
P.S. After a couple of answers around switch construct let me show a chunk of the real code. This is just one example.
typedef enum
{
EVENTS_STATISTICS_COLLECTOR_POOL_TIMEOUT ,
EVENTS_STATISTICS_COLLECTOR_POOL_FAILED ,
EVENTS_STATISTICS_COLLECTOR_SENT_TO_PIPELINE ,
// 50 entries like this
EVENTS_STATISITCS_LAST ,
} events_statistics_t;
uint64_t events_statistics[EVENTS_STATISITCS_LAST];
const char *event_statistics_names[] = {
"collector_pool_timeout ",
"collector_pool_failed ",
"collector_sent_to_pipeline ",
// and so on ...
};
static inline void events_statistics_bump_counter(events_statistics_t counter)
{
events_statistics[counter]++;
}
// The actual function is a generic one which prints arbitrary pairs
// But this one gives an idea
void print_statistics()
{
int col = 0;
static const int COLUMNS = 3;
printf("\n");
for (int i = 0;i < EVENTS_STATISITCS_LAST;i++)
{
printf("%-30s %9lu", event_statistics_names[i], events_statistics[i]);
col++;
if ((col % COLUMNS) == 0)
printf("\n");
else
printf("%4s", "");
}
if ((col % COLUMNS) != 0)
printf("\n");
}
P.S.2 What I wanted to say in the previous P.S. is that "switch" gives too much freedom to the compiler. I want to ensure that the lookup is a simple table and not some double indexed array or if/else branches
P.S.3 Here is another example of an initialised array. The array contains hooks and it is of an extreme importance to call the correct function.
typedef struct
{
const int id;
const events_process_t processor;
uint64_t counter;
} events_process_table_t;
static events_process_table_t events_processors[EVENT_ID_LAST] =
{
{EVENT_ID_OPEN , (events_process_t)events_process_open },
{EVENT_ID_OPENAT , (events_process_t)events_process_open },
// and so on for 30 lines
};
static_assert(arraysize(events_processors) == EVENT_ID_LAST, "Update the table of events processors");
void some_code(int event_id)
{
events_process_table_t *table = &events_processors[event_id];
if (event_id == table->id)
{
// Looks alright and I can use the table->processor
// .....
}
}