I've never seen this inside a class and would recommend you to never do it if you want to still understand the code the other day.
That said, there is a case where I find this technique acceptable and that is when you have a large table from which you need to generate multiple constructs like an enum and an attribute table. Let's have two files like:
foobars.h:
enum Foobars {
#define FOOBAR(id, description, args) FOOBAR_##id,
#include "foobars.tab"
#undef FOOBAR
};
extern const char *foobar_names[];
const char *parse_foobar(Foobars fb, const char *input);
foobars.cpp:
#include "foobars.h"
const char *foobar_names[] = {
#define FOOBAR(id, description, args) description,
#include "foobars.tab"
#undef FOOBAR
};
const char *parse_foobar(Foobars fb, const char *input) {
switch(fb) {
#define INT get_int(&input)
#define FLOAT get_float(&input)
#define STRING get_string(&input)
#define FOOBAR(id, description, args) args
#include "foobars.tab"
#undef FOOBAR
}
return input;
And the magic is in "foobars.tab" (it's special, so I recommend not calling this anything.h or anything.hpp or any other common suffix):
/* CAUTION! This file is included using C preprocessor in the middle of various structures
* It must not contain anything except definitions of foobars in the FOOBAR macro and
* comments. Don't forget NOT to write semicolons; some of the structures are
* comma-separated and some semicolon-separated. FOOBAR will be defined appropriately before
* including this file. */
FOOBAR(NULL, "Empty command, does nothing", {}) // NO semicolon!
// Also some preprocessors don't like empty arguments, so that's why {}.
// (void)0 is an alternative.
FOOBAR(FOO, "Foo bars and bazes", a = INT; b = STRING)
FOOBAR(BAR, "Bars, but does not baz", x = FLOAT)
...
The other option is defining a macro to content of the special include. If the table is short, the macro is easier to read, but if the file is long, the special file makes more sense.
The last option is to have the table in altogether different format and generate the code, but that involves writing some special script for building it and this does not.