C++ in Xcode: Use of undeclared identifier from macro generated enum - c++

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.

Related

Using a enum class from a c++ header in a c header

I am writing a c wrapper around a c++ library.
In the c++ there are enum classes used as types for function arguments.
How do I use theme correctly in the c header.
One ugly way would be to use int's in the c function and cast theme in the wrapper function to the enum type. But this gives the user of the c function no clue about the valid values, and it is really hard to check if the value is valid.
cpp header
namespace GPIO
{
enum class Directions
{
UNKNOWN,
OUT,
IN,
HARD_PWM
};
void setup(int channel, Directions direction, int initial = -1);
}
c wrapper header
int setup(int channel, int direction, int initial);
c wrapper code
int setup(int channel, int direction, int initial)
{
GPIO::setup(channel, static_cast<GPIO::Directions>(direction), initial);
return 0;
}
What would be a good way to give the user of the c functions the benefits of the enum classes in the c++ library. Because it is not my library, I would like to not change too much of the code in the library.
There would be the option to extract the enum classes to a different file and include it in the original header. But I don't know how to define it correctly, so I don't have to change the naming in the cpp library and still can use it in the c header.
You can not do it. It is impossible to use C++ features from C code. You are creating C wrapper for C++ function, why can not you create also C wrapper for enum? The only question is how to be sure that both enums have the same values. You can check it compile time after the small code change:
cpp header:
namespace GPIO
{
enum class Directions
{
UNKNOWN,
OUT,
IN,
HARD_PWM,
SIZE
};
}
c wrapper header:
enum GPIO_Directions
{
GPIO_Directions_UNKNOWN,
GPIO_Directions_OUT,
GPIO_Directions_IN,
GPIO_Directions_HARD_PWM,
GPIO_Directions_SIZE
};
c wrapper code:
int setup(int channel, GPIO_Direction direction, int initial)
{
static_assert(GPIO::Directions::SIZE == GPIO_Directions_SIZE,
"c wrapper enum must be equal to c++ enum");
GPIO::setup(channel, static_cast<GPIO::Directions>(direction), initial);
return 0;
}
Assuming you are in control of the C++ headers, too, then you can let the pre-processor generate the enum definitions; you need a set of macros for:
genEnumDefine.h:
// DON'T want include guards!
// otherwise including several headers defining enums that way would fail!
#ifdef __cplusplus
#define ENUM_DEFINITION(NAMESPACE, NAME, CONTENT) \
namespace NAMESPACE \
{ \
enum class NAME \
{ \
CONTENT(NAMESPACE, NAME) \
}; \
}
#define ENUM_ENTRY(N, E, V) V
#else
#define ENUM_DEFINITION(NAMESPACE, NAME, CONTENT) \
enum NAMESPACE##_##NAME \
{ \
CONTENT(NAMESPACE, NAME) \
};
#define ENUM_ENTRY(N, E, V) ENUM_ENTRY_(N, E, V)
#define ENUM_ENTRY_(N, E, V) N##_##E##_##V
#endif
genEnumUndef.h:
#undef ENUM_DEFINITION
#undef ENUM_ENTRY
#ifndef __cplusplus
#undef ENUM_ENTRY_
#endif
Now you can define an enum simply as:
#include <genEnumDefine.h>
#define ENUM_N_E(NAMESPACE, NAME) \
ENUM_ENTRY(NAMESPACE, NAME, E1 = 1), \
ENUM_ENTRY(NAMESPACE, NAME, E2), \
ENUM_ENTRY(NAMESPACE, NAME, E3)
ENUM_DEFINITION(N, E, ENUM_E)
#include <genEnumUndef.h>
You could even define both enums in one single header! You would change the check for __cplusplus for a custom definition and could then do the following:
#define ENUM_N_E(NAMESPACE, NAME) \
ENUM_ENTRY(NAMESPACE, NAME, E1 = 1), \
ENUM_ENTRY(NAMESPACE, NAME, E2), \
ENUM_ENTRY(NAMESPACE, NAME, E3)
#ifdef __cplusplus
#define GEN_ENUM_CPP 1
#include <genEnumDefine.h>
ENUM_DEFINITION(N, E, ENUM_E)
#include <genEnumUndef.h>
#undef GEN_ENUM_CPP
#endif
#include <genEnumDefine.h>
ENUM_DEFINITION(N, E, ENUM_E)
#include <genEnumUndef.h>
Just for illustration...
Life demo (implicit C/C++ check variant).
You cannot use the C++ code in C because it hasn't been written in common subset of the languages.
You can define a corresponding enum in the C wrapper like this for example:
// C
enum Wrapper_Directions
{
Wrapper_Directions_UNKNOWN,
Wrapper_Directions_OUT,
Wrapper_Directions_IN,
Wrapper_Directions_HARD_PWM,
};
int wrapper_setup(int channel, enum Wrapper_Directions direction, int initial);

#defined enum on Doxygen

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:

Function definition not found for #define

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; \
}

Force compilation to fail if a struct member with a particular name exists

Suppose bad_name is a restricted identifier for example that I do not want to be part of the struct. I am looking for a mechanism to force a compilation failure in that case.
example.h
struct example {
int okay_name;
int bad_name;
}
main.cc
#include "example.h"
int main() {
example ex;
// cause compilation to fail here if bad_name is a member of ex
return 0;
}
There are probably ways to cause a failure at runtime by simulating reflection, but is there a way to do this at compile time?
You can define bad_name to be something that would cause a compile time error. For example, nothing:
#define bad_name
gives on GCC
error: declaration does not declare anything [-fpermissive]
int bad_name;
You can simulate static assertions in C like this:
#define bad_name xxx; char static_assertion_bad_name_used[-1];
struct example {
int okay_name;
int bad_name;
};
which in GCC gives:
main.c:6: error: size of array ‘static_assertion_bad_name_used’ is negative
The advantage of this technique is that the error message gives you a reminder of what the problem is (even if slightly obscurely).
Update After reading this I found out that MS Visual Studio does not include the actual variable name in the error message if the array size is negative. Here is an alternative:
#define bad_name xxx; int static_assertion_bad_name_used : 0;
The error message in GCC is then:
main.c:5: error: zero width for bit-field ‘static_assertion_bad_name_used’
and apparently something similar in VS.
Also if using a more up to date compiler you can use _Static_assert, which would be a lot cleaner.
You may use the following:
#include <cstdint>
#define DEFINE_HAS_SIGNATURE(traitsName, funcName, signature) \
template <typename U> \
class traitsName \
{ \
private: \
template<typename T, T> struct helper; \
template<typename T> \
static std::uint8_t check(helper<signature, &funcName>*); \
template<typename T> static std::uint16_t check(...); \
public: \
static \
constexpr bool value = sizeof(check<U>(0)) == sizeof(std::uint8_t); \
}
DEFINE_HAS_SIGNATURE(has_bad_name, T::bad_name, decltype(&T::bad_name));
Then check with a static_assert (need C++11):
static_assert(!has_bad_name<example>::value, "");
Suppose bad_name is a restricted identifier for example that I do not
want to be part of the struct. I am looking for a mechanism to force a
compilation failure in that case.
This is not fully portable, but at least in VC++ and GCC you can mark the identifier as deprecated and, if you want, elevate the warning it gives to an error.

How can I use Enum::GetName in unmanaged C++

I am using managed extensions in VS 2008
I want to print the name of an en enum value
This code used to be fine VS 2003
Enum::GetName(__typeof(COMMAND_CODES),__box(iTmp))
but now I get a comile error
here is my enum
typedef enum { /* Command codes */
UMPC_NULL = 0,
} COMMAND_CODES
Any clues ?
;
As far as I know, that is not possible in plain C++ since it doesn't have reflection.
You can use macros in plain C++ to workaround it:
#define COMMAND_CODES \
ENUM_OR_STRING(CODE1), \
ENUM_OR_STRING(CODE1),
// Enum
#define ENUM_OR_STRING(x) x
enum CommandCodes
{
COMMAND_CODES
};
#undef ENUM_OR_STRING
// Names
#define ENUM_OR_STRING(x) #x
char *CommandCodeNames[] =
{
COMMAND_CODES
};
#undef ENUM_OR_STRING
Now the name of enum member is as easy to get as CommandCodeNames[(int)commandCode].
Can you use rtti typeid() and use the name() field?
Edit: From comment:
Enum::GetName(COMMAND_CODES::typeid,iTmp)