So I have a #define that creates a "MY_ENUM" (minimal version)
#define MY_ENUM(ename, ...) \
namespace ename { \
enum ename { __VA_ARGS__, COUNT }; \
static std::string _Strings[COUNT]; \
static inline size_t size() {return COUNT;} \
}
This generates useful enums that can be created as:
/**
* #brief List of elements
*/
MY_ENUM(enuElements, Element1, Element2, Element3, Element4, Element5, Element6)
But generating the doc with doxygen doesn't seem to work => it mixes one enum with the following and some don't even appear.
I set:
MACRO_EXPANSION = YES
SKIP_FUNCTION_MACROS = NO
PREDEFINED = MY_ENUM(x) =
For what I have read, the answer is a proper setting of PREDEFINED but I haven't achieved, does anyone know how to create a document with this kind of defines?
Edit
Doxygen Version : 1.8.0
About why I think the clue is in PREDEFINED (but I might as well be wrong):
The site of Doxygen when talking about macros
This and this questions on SO
With the following code:
/// \file
#define MY_ENUM(ename, ...) \
namespace ename { \
enum ename { __VA_ARGS__, COUNT }; \
static std::string _Strings[COUNT]; \
static inline size_t size() {return COUNT;} \
}
/**
* #brief List of elements
*/
MY_ENUM(enuElements, Element1, Element2, Element3, Element4, Element5, Element6)
The setting (besides the default settings):
MACRO_EXPANSION = YES
and doxygen 1.9.1 I got:
Related
I am getting a weird error for one of my macros. The names are changed, but besides that the code is exactly the same as the one in my project. Its purpose is automatic a process I write many times troughout my code.
#ifdef add
#undef add
#endif
#define add(name, temp) \
struct name<temp> \
{ \
static constexpr r = true; \
}
Here is the error:
Function definition for 'add' not found.
explicit type is missing ('int' assumed)
It's expanding the code properly and showing me that too, but it seems either it is very confused about what's going on or I do not understand the error.
I am using Visual Studio 2019, so the VC++19 compiler.
I think you've forgotten bool keyword as compiler message suggested but as int
#ifdef add
#undef add
#endif
#define add(name, temp) \
struct name<temp> \
{ \
static constexpr bool r = true; \
}
For example, I saw source code like the following. Can we use #define in a function? How does it work? (more information: this code is what I copied from openvswitch source code):
void *
ofputil_put_action(enum ofputil_action_code code, struct ofpbuf *buf)
{
switch (code) {
case OFPUTIL_ACTION_INVALID:
#define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) case OFPUTIL_##ENUM:
#include "ofp-util.def"
OVS_NOT_REACHED();
#define OFPAT10_ACTION(ENUM, STRUCT, NAME) \
case OFPUTIL_##ENUM: return ofputil_put_##ENUM(buf);
#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
case OFPUTIL_##ENUM: return ofputil_put_##ENUM(buf);
#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
case OFPUTIL_##ENUM: return ofputil_put_##ENUM(buf);
#include "ofp-util.def"
}
OVS_NOT_REACHED();
}
#define OFPAT10_ACTION(ENUM, STRUCT, NAME) \
void \
ofputil_init_##ENUM(struct STRUCT *s) \
{ \
memset(s, 0, sizeof *s); \
s->type = htons(ENUM); \
s->len = htons(sizeof *s); \
} \
\
struct STRUCT * \
ofputil_put_##ENUM(struct ofpbuf *buf) \
{ \
struct STRUCT *s = ofpbuf_put_uninit(buf, sizeof *s); \
ofputil_init_##ENUM(s); \
return s; \
}
#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
OFPAT10_ACTION(ENUM, STRUCT, NAME)
#define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
OFPAT10_ACTION(ENUM, STRUCT, NAME)
#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
void \
ofputil_init_##ENUM(struct STRUCT *s) \
{ \
memset(s, 0, sizeof *s); \
s->type = htons(OFPAT10_VENDOR); \
s->len = htons(sizeof *s); \
s->vendor = htonl(NX_VENDOR_ID); \
s->subtype = htons(ENUM); \
} \
\
struct STRUCT * \
ofputil_put_##ENUM(struct ofpbuf *buf) \
{ \
struct STRUCT *s = ofpbuf_put_uninit(buf, sizeof *s); \
ofputil_init_##ENUM(s); \
return s; \
}
#include "ofp-util.def"
#define is a preprocessor directive: it is used to generate the eventual C++ code before it is handled to the compiler that will generate an executable. Therefore code like:
for(int i = 0; i < 54; i++) {
#define BUFFER_SIZE 1024
}
is not executed 54 times (at the preprocessor level): the preprocessor simply runs over the for loop (not knowing what a for loop is), sees a define statement, associates 1024 with BUFFER_SIZE and continues. Until it reaches the bottom of the file.
You can write #define everywhere since the preprocessor is not really aware of the program itself.
Sure this is possible. The #define is processed by the preprocessor before the compiler does anything. It is a simple text replacement. The preprocessor doesn't even know if the line of code is inside or outside a function, class or whatever.
By the way, it is generally considered bad style to define preprocessor macros in C++. Most of the things they are used for can be better achieved with templates.
You can use it inside a function, but it is not scoped to the function. So, in your example, the second definitions of a macro will be a redefinition and generate an error. You need to use #undef to clear them first.
You can use #define anywhere you want. It has no knowledge of functions and is not bound by their scope. As the preprocessor scans the file from top-to-bottom it processes #defines as it sees them. Do not be misled (by silly code like this!) into thinking that the #define is somehow processed only when the function is called; it's not.
How does it work? All C/C++ files are first processed by... the preprocessor.
It doesn't know anything about C nor C++ syntax. It simply replaces THIS_THING with ANOTHER THING. That's why you can place a #define in functions as well.
Sure. #define is handled by the preprocessor which occurs well before the compiler has any sense of lines of code being inside functions, inside parameters lists, inside data structures, etc.
Since the preprocessor has no concept of C++ functions, it also means that there is no natural scope to macro definitions. So if you want to reuse a macro name, you have to #undef NAME to avoid warnings.
I have a config file containing string representations of an enum. There are a lot of different enum values. After loading the config, I need to work out enum values from it string representations. Ignoring macros, the only way I can think of doing this would be to create a hideous lookup function doing a string comparison against every possible value. Something like:
typedef enum Fields
{
FieldFlagNone,
FieldFlagOperation,
FieldFlagFormat,
...
}
Fields getFieldEnum(string fieldName){
if( fieldName.compare("FieldFlagNone") == 0 ){
return FieldFlagNone;
}else if( fieldName.compare("FieldFlagOperation") == 0 ){
return FieldFlagOperation;
}else if( fieldName.compare("FieldFlagFormat") == 0 ){
return FieldFlagFormat;
...
}
Is there a faster or more concise way of achieving the desired result?
You can use std::unordered_map<std::string, Fields>, that will speed up the conversion from linear time to constant time:
std::unordered_map<std::string, Fields> fieldsLookupTable {
{ "FieldFlagNone", FieldFlagNone },
...
};
To make it more concise you can use some macros:
#define LOOKUP_TABLE_ENTRY(x) { #x, x }
And then:
std::unordered_map<std::string, Fields> fieldsLookupTable {
LOOKUP_TABLE_ENTRY(FieldFlagNone),
LOOKUP_TABLE_ENTRY(FieldFlagOperation),
...
};
If you want to go really hardcore on eliminating duplication, you can do something like this:
#define ENUM_MODE_DEFINE 0
#define ENUM_MODE_LOOKUP 1
#define ENUM_BEGIN(x) \
#if ENUM_MODE == ENUM_MODE_DEFINE \
typedef enum x { \
#else \
#define LOOKUP_TABLE_NAME x ## LookupTable \
std::unordered_map<std::string, x> LOOKUP_TABLE_NAME; \
#endif
#define ENUM_ENTRY(x) \
#if ENUM_MODE == ENUM_MODE_DEFINE \
x, \
#else \
LOOKUP_TABLE_NAME[#x] = x; \
#endif
#define ENUM_END \
#if ENUM_MODE == ENUM_MODE_DEFINE \
} \
#else \
#undef LOOKUP_TABLE_NAME \
#endif
And then define your enum like this:
#define FIELDS \
ENUM_BEGIN(Fields) \
ENUM_ENTRY(FieldFlagNone) \
ENUM_ENTRY(FieldFlagOperation) \
...
ENUM_END
And where previously there was the enum definition, now there will be this:
#define ENUM_MODE ENUM_MODE_DEFINE
FIELDS
And somewhere else where you had the lookup table, you say this:
#define ENUM_MODE ENUM_MODE_LOOKUP
FIELDS
Basically the FIELDS macro uses the ENUM_BEGIN, ENUM_ENTRY and ENUM_END macros, which generate different code based on the value of ENUM_MODE. If you define it to be ENUM_MODE_DEFINE, then FIELDS will generate the enum definition. If you set it to ENUM_MODE_LOOKUP, it'll generate fieldsLookupTable.
This way we only used the enum entry names in FIELDS, so if you change something there, the lookup table and the enum definition will change automatically and won't go out of sync.
I am given this set of code that have a macro generate an enumeration during compile time.
MakeEnum4(EnumName, Value1, Value2, Value3, Value4);
MakeEnum4 is the alias for another macro function with the following definition:
/// Here _Indexed() is an empty macro
#define MakeEnum4(name,v1,v2,v3,v4) _Expand4(name, _Indexed(), v1, v2, v3, v4)
_Expand4 is defined as follows:
#define _Expand4(name, mode, value1, value2, value3, value4) \
namespace name \
{ \
typedef uint Type; \
// cstr is typedef as const char* \
static const cstr EnumName = #name; \
enum Enum { value1 = mode 0, value2 = mode 1, value3 = mode 2, \
value4 = mode 3 }; \
enum { Size = 4 }; \
static const cstr Names[] = { #value1, #value2, #value3, #value4, NULL }; \
} \
So here's the issue:
In some header file an enum was generated, let's call it Declaration.h:
//in Declaration.h
MakeEnum4(SomeEnum, TypeA, TypeB, TypeC, TypeD);
Then in another file call FooHeader.h, a template function is calling this generated enumeration SomeEnum:
//in FooHeader.h
template < typename type >
SomePtr* Foo(cstr name, SomeType*& someType, /*unrelated function pointer*/)
{
someType = new SomeType(name, sizeof(type), CompileTimeId<type>(), SomeEnum::TypeA);
//...
}
Here SomeEnum is flagged by the C++ compiler that Xcode uses as "Use of undeclared identifier 'SomeEnum'". The same set of code compile fine on Visual Studio 2010. And this project is a cross-platform project for a same set of C++ libraries to be ported over to Apple's platform.
I am thinking that it might be due to the enumeration not being generated in time for FooHeader.h's translation unit but I have no idea how to get around it. Any insight on this is appreciated.
Sorry if the code I provided are cryptic, that's because the content is under some very strict NDA on my end.
How to put the Q_PROPERTY macro inside another, helper-macro?
#define SimpleAllinOne(member, _type) \
public: \
void Set##member(_type _arg_##member) \
{ \
m_##member = _arg_##member;\
} \
_type Get##member() const\
{ \
return m_##member;\
} \
private: \
_type m_##member; \
Q_PROPERTY(_type member READ Get##member WRITE Set##member)
.. does not work. Preprocessor output (gcc -E flag or nmake/jom /P flag) shows the (working) setter/getter methods and corresponding member variable but not a single character for the Q_PROPERTY line.
Update: It seems to work with Qt5.1 which expands the user macros properly. Qt4.8 does not work, Qt5.0 has not been tested. See #QTBUG-35 (thanks to ??).
moc in Qt4.x does not recognize Q_ macros within preprocessor macros.
moc in Qt5.x expands the preprocessor macros before parsing the Q_ macros.
You have a bug too in the lines
Set##member##(_type _arg_##member) \
_type Get##member##() const\
because of ##() which is evaluated to
SetArg(
_type GetArg(
by gcc and rejected (MSVC ignores it).
Try the following corrected version and it should work:
#define MachAlles(member, _type) \
public: \
/**
* Set member of type _type.
* #see m_##member for a more detailed description
*/ \
void Set##member(_type _arg_##member) \
{ \
m_##member = _arg_##member;\
} \
/**
* Get member of type _type.
* #see m_##member for a more detailed description
*/ \
_type Get##member() const\
{ \
return m_##member;\
} \
private: \
_type m_##member; \
Q_PROPERTY(_type member READ Get##member WRITE Set##member)