I have some code, that has namespace configurable by user as this:
#pragma once
#ifdef GRAPHICS_NAMESPACE
namespace GRAPHICS_NAMESPACE {
#endif
class Foo {
}
#ifdef GRAPHICS_NAMESPACE
}
#endif
And in cpp file, there is
#ifdef GRAPHICS_NAMESPACE
using namespace GRAPHICS_NAMESPACE;
#endif
Now I have a problem. I have defined -DGRAPHICS_NAMESPACE=Graphics and I have a header with:
#pragma once
#include "Foo.h"
class Bar {
Foo foo;
}
But Foo foo gives me error, since Foo is in namespace now named Graphics. I can solve this with adding
#ifdef GRAPHICS_NAMESPACE
using namespace GRAPHICS_NAMESPACE;
#endif
to my header, but that is not very safe since it will be using namespace everywhere where I include my header. Is there any other solution?
Although I would say this is not the optimal way to arrange things, I've seen worse and the solution to your problem is rather straightforward:
class Bar {
#ifdef GRAPHICS_NAMESPACE
GRAPHICS_NAMESPACE::
#endif
Foo foo;
}
If you insist on sticking with this design, you can clean this up, somewhat, by defining a 2nd macro:
#ifdef GRAPHICS_NAMESPACE
#define GRAPHICS_CLASS(x) GRAPHICS_NAMESPACE:: x
#else
#define GRAPHICS_CLASS(x) x
#endif
And then declare things along the lines of:
class Bar {
GRAPHICS_CLASS(Foo) foo;
}
Finally, if you insist on relying on the preprocessor for this kind of critical functionality, you may want to consider spending a little bit more time reading what your C++ book says on this topic. These are fairly basic, straightforward uses of the C++ preprocessor, which I expect should be fully explained in any introduction on what a C++ preprocessor is, and how it works.
I would do it like this:
#ifdef GRAPHICS_NAMESPACE
#define GRAPHICS GRAPHICS_NAMESPACE
#else
#define GRAPHICS
#endif
...
GRAPHICS::Foo
Related
The following code does not compile:
#define SOME_MACRO(x,y) x+y
#define ADD_ONE_TO(x) SOME_MACRO(x,1)
#undef SOME_MACRO
int main(){
ADD_ONE_TO(1);
}
Is there any hack to either:
Prevent code duplication by having common functionality in SOME_MACRO and using it in other macros BUT undef`ing it to prevent its usage in common user-code.
Somehow making it so the ADD_ONE_TO macro just copy-pastes the macros it uses instead of referncing them.
Preventing user-code from accessing and using SOME_MACRO but allowing it to be used in other specific parts of code(other, select, macros)
Hide the implementation of macros by disallowing access(undef or otherwise) to the macros inside the macro which we want to hide the implementation of.
When using GNU CPP you could use #pragma GCC poison, for example:
#include <stdio.h>
#define print(...) printf(__VA_ARGS__)
#pragma GCC poison printf
int
main ()
{
print("hi, %s", "there!"); /* Ok */
printf("oh %s", "no!"); /* ERROR! use of poisoned keyword */
}
Tested and it works!
I am trying to make a C++/CLI wrapper for my native C++ project so that I can use it in C#. So far I've wrapped the classes and functions that I need, but I've been trying to find a way to do the same for Enums without having to copy and paste the code to the wrapper.
I've tried looking up ways to wrap enums, but it seems that there's no way to use the enums that are from the native C++ code without having to cast/rewrite the code in the wrapper layer. So I found a solution where you use preprocessor directives and include the enums twice into the wrapper, but it seems not to be working for some reason.
Native Code (Enums.h)
#pragma once
#if defined MANAGED && !defined ENUMS_MANAGED_H
#define ENUMS_MANAGED_H
#define NAMESPACE managed
#define ENUM public enum class
#elif !defined MANAGED && !defined ENUMS_NATIVE_H
#define ENUMS_NATIVE_H
#define NAMESPACE native
#define ENUM enum class
#endif
namespace NAMESPACE
{
ENUM numbers
{
ONE = 1,
TWO = 2,
}
}
Managed Code (Wrapper.h)
#pragma once
#ifndef WRAPPER_H
#define WRAPPER_H
#include "Native.h" //Other native code which also includes Enums.h
#define MANAGED
#include "Enums.h"
namespace managed
{
managed::numbers num = managed::numbers::ONE; //managed does not contain 'numbers'
}
#endif //!WRAPPER_H
C# Code (Main.cs)
using managed; //managed project added as reference
static void main(String[] args)
{
Console.WriteLine((int) numbers.ONE); //managed does not contain 'numbers'
}
I expect to be able to use managed::numbers in the managed project alongside native::numbers. I also expect to be able to use the numbers enum in C#. However, visual studio has not been able to do this. I've tried rearranging the includes as well but that doesn't seem to work.
I made a test file in the managed class that includes Enums.h, but not Native.h:
TestFile.h
#ifndef TESTFILE_H
#define TESTFILE_H
#define MANAGED
#include "Enums.h"
namespace managed
{
managed::numbers num = managed::numbers::ONE; //Works
}
#endif //!TESTFILE_H
This works, but I also need to be able to include Native.h and use the enums from there as well
Edit:
Using #robthebloke answer,
What I got to work is in Enums.h to do:
#pragma once
// to disable error in EnumsImpl.h
#define BUILDING_ENUMS
#include "EnumsImpl.h"
#undef BUILDING_ENUMS
And then in Wrapper.h:
#pragma once
#ifndef WRAPPER_H
#define WRAPPER_H
#include "Native.h"
#define BUILDING_ENUMS
#define MANAGED
#include "EnumsImpl.h"
#undef MANAGED
#undef BUILDING_ENUMS
#endif
Is there any way to just use one file instead of having to use EnumsImpl.h?
EnumsImpl.h
// guard against incorrect usage.
#if !defined(BUILDING_ENUMS)
#error "Do not include this file directly, include Enums.h instead"
#endif
// choose macros for below
#if defined MANAGED
#define NAMESPACE managed
#define ENUM public enum class
#elif !defined MANAGED
#define NAMESPACE native
#define ENUM enum class
#endif
namespace NAMESPACE
{
ENUM numbers
{
ONE = 1,
TWO = 2,
}
}
#undef NAMESPACE
#undef ENUM
Enums.h
#pragma once
// to disable error in EnumsImpl.h
#define BUILDING_ENUMS
// unmanaged
#include "EnumsImpl.h"
// managed
#define MANAGED
#include "EnumsImpl.h"
// remove temp defines
#undef MANAGED
#undef BUILDING_ENUMS
An Alternative...
#define DefEnum(NAMESPACE, ENUM) \
namespace NAMESPACE \
{ \
ENUM numbers \
{ \
ONE = 1, \
TWO = 2, \
}; \
}
DefEnum(dave, enum class);
I want to use macros to quickly create inlined functions in headers, these functions are related to a base class which I am subclassing. I'll put the definitions inside the base class header but I do not want to pollute everything that include these headers with all macro definitions, so I would like to write something like this (which unfortunately doesn't work):
#define BEGIN_MACROS \
#define MACRO_1(...) ...\
#define MACRO_2(...) ...\
#define MACRO_3(...) ...
#define END_MACROS \
#undef MACRO_1\
#undef MACRO_2\
#undef MACRO_3
And then use it like:
BEGIN_MACROS
MACRO_1(...)
MACRO_2(...)
MACRO_3(...)
END_MACROS
perhaps should I use something like this?
#include "definemacros.h"
MACRO_1(...)
MACRO_2(...)
MACRO_3(...)
#include "undefmacros.h"
And put definitions and "undefinitions" in two separate headers...
Or is there a better approach overall to overcome this kind of problems?
Or do you suggest to avoid at all the use of macros and/or macros in headers?
Edited to include specific use case:
definition:
#define GET_SET_FIELD_VALUE_INT(camelcased, underscored)\
inline int rget ## camelcased () { return this->getFieldValue( #underscored ).toInt(); }\
inline void rset ## camelcased (int value) { this->setFieldValue( #underscored , value); }
use:
class PaymentRecord : public RecObj
{
public:
GET_SET_FIELD_VALUE_INT(PriceIndex, price_index)
//produces this
inline int rgetPriceIndex() { return this->getFieldValue("price_index").toInt(); }
inline void rsetPriceIndex(int value) { this->setFieldValue("price_index", value); }
};
you can not stack up more defines into single line (at least to my knowledge... What I would try to do is encapsulate those into 2 separate files instead like this:
file macro_beg.h:
#define MACRO_1(...) ...
#define MACRO_2(...) ...
#define MACRO_3(...) ...
file macro_end.h:
#undef MACRO_1
#undef MACRO_2
#undef MACRO_3
It just like your second case but the macros are not in single line ...
#include "macro_beg.h"
MACRO_1(...);
MACRO_2(...);
MACRO_3(...);
#include "macro_end.h"
But as Some programmer dude commented this might not work properly or at all depending on the compiler preprocessor and macro complexity or nesting with class/template code. For simple stuff however this should work.
I am writing a class (separated in header file myClass.h and implementation file myClass.cpp) which I want to use with both standard C++ and the Qt framework. Since the differences in the code are very small (and I wanted to try it out once), I decided to #define USINGQT 1 in order to toggle the small sections of code via
#if USINGQT==1
//Qt code
#else
//standard code
#endif
Now I came to the conclusion that it'd be convenient to use QStrings throughout the whole class instead of std::strings when "activating" the USINGQT switch. However, the method above would render the code extremely messy. My solution (in the header file):
#if USINGQT==1
#include <QString>
#define string QString
#else
#include <string>
#define string std::string
#endif
Now to the question:
Consider the files to look like
---myclass.h-------------------------
#ifndef MYCLASS_H
#define MYCLASS_H
#define USINGQT 1 //1=on, else off
#if USINGQT==1
#include <QString>
#define string QString
#else
#include <string>
#define string std::string
#endif
namespace mySpace {
class MyClass {
string qtOrStd;
string foo();
//etc...
};
} //namespace
#endif //MYCLASS_H
-------------------------------------
---myclass.cpp-----------------------
#include "myclass.h"
using namespace mySpace;
//implementations
string MyClass::foo() //string symbol occurs, as does the USINGQT
-------------------------------------
Where is the correct place to #undef the string and USINGQT symbols? At the end of the header file (which would then require a redefinition and "undefinition" in the implementation file as well) or just at the end of the implementation file?
I should capitalize the string macro as well, shouldn't I...? >.>
If I put the macro definitions inside the namespace I receive approx. 800 error messages with entries like "no member of mySpace::std" among others. Can you say something about that without further information? Otherwise it compiles just fine.
EDIT: I may should have told you that I want the macros to only apply to this specific header AND its implementation file. Despite the fact that I will of course go for the typedefs - in the macro case, I'd guess, I should place the #undef at the end of the implementation file. Because the macros won't be redefined because of the include guards.
Firstly you do not need to toggle USINGQT by making it equal to 1 you can simply #define USINGQT and then use #ifdef USINGQT for your if statement.
In terms of your ability to toggle which string library you use I would suggest using a typedef alongside a pre-processor if statement. This would avoid any namespace issues. An example of this is shown below.
// -------------- Some config file -------------=
#define USINGQT
// -------------- MyClass.h --------------------=
// Header guard
#ifndef MyClass
#define MyClass
// Conditional Header types
#ifdef USINGQT
// QT OPTION
typedef QString my_string;
#else
// Not QT
typedef std::string my_string;
#endif
class MyClass {
public:
my_string some_string;
MyClass()
{
my_string = "hello world";
}
};
#endif
I do not see any reason to #undef the macro. Surely you want all your code to be compiled with one state of that macro? Then you will not need to #undef it.
However, I also strongly suggest you to use typedef for your string definition. This will anyway be clearer, you will not think about capitalizing it, and you can even put it into your namespace. Use :: if you need to access global namespace:
#define USINGQT
#ifdef USINGQT
#include <QString>
#else
#include <string>
#endif
namespace mySpace {
#ifdef USINGQT
typedef ::QString string;
#else
typedef ::std::string string;
#endif
}
Also note (as shown above) that if you need just a boolean value for macro, then you don't need to make it 1 or 0, just use #ifdef/#ifndef.
After this, in your .cpp, just use mySpace::string and never bother about macroses.
You don't have to #undef macros unless another file tries to re-define it. You can't #undef a macro before you're done using it and therefore, if you #define a macro in a header and want to use it in files that include the header, then you cannot #undef it in that header.
1) Where is the correct place to #undef the string and USINGQT symbols? At the end of the header file ...
Only if you use it in that header... but you apparently do use it a file that includes the header, so no.
or just at the end of the implementation file?
Undefining a macro at the end of an implementation file is pointless, because there will be no code after the end of the file to which the macro applies anymore. Just let it stay defined.
2) I should capitalize the string macro as well, shoudln't I...? >.>
You don't have to capitalize macros, but it's a convention. That said, defining a macro by the same name as a standard class is just asking for trouble. You should use a typedef instead of a macro here in order to get meaningful error messages in case of name conflicts. And use another name like string_t or define the typedef in a namespace.
3) If I put the macro definitions inside the namespace I receive approx. 800 error messages
The errors don't come from defining the macros inside a namespace. The errors come from using the macros as-if they were part of the namespace. For example, if you say:
namespace mySpace {
#define string std::string
}
mySpace::string s;
then the string will be replaced with std::string and the typename becomes mySpace::std::string. Since you haven't defined a std namespace inside mySpace, this is wrong. What you need to understand is that namespaces don't have any effect on preprocessor macros. Which makes it harder to avoid name conflicts which is one reason why you usually want to avoid pre-processor macros.
If the USINGQT macro applies to all of your code such that it must be same for all files, you may want to not define it in a header at all, but instead pass it as an argument to the compiler. That way you can easily compile with different values without changing a file.
About your edit:
Even if you want the macro to be defined differently in another file, then undefining it at the end of the implementation has no effect, because the implementation file won't be included by the files that include the header. You should avoid a situation where you need multiple, different definitions (or lack of definitions) of macros, but if you're in such a situation, then yes, your only solution is to define it separately in each file that needs it and then undefine at the end of any header that needs it. But you're not in a such situation because you can use a type alias instead.
I'm including header files which require certain pro-processor #defines to be present, however I do not want this to pollute the rest of my code e.g.:
// FOO may or may not already be defined here
#define FOO
#include "Bar.h"
#undef FOO
// FOO should be defined or not, as per the starting state
I'm thinking along the lines of:
#ifdef FOO
#define FOO_DEFINED
#endif
#define FOO
#include "Bar.h"
#ifndef FOO_DEFINED
#undef FOO
#else
#undef FOO_DEFINED
#endif
Questions:
Will the above work i.e. restore all macro definitions (or lack of) to the state they were in beforehand?
Is there perhaps a simpler solution?
Does it matter if FOO was already defined when I #define it? Should I add another #ifndef to protect against this?
It appears that in your example, Bar.h cares only whether FOO is defined or not, and not the actual expression bound to it. Furthermore, if someone else (I presume your code example is, itself, in a header file) defines FOO and cares about the expression bound to it, you don't want to make the mistake of redefining FOO with an empty expression. If so, you might want to simplify:
#ifndef FOO
#define FOO
#define UNDEF_FOO
#endif
#include "Bar.h"
#ifdef UNDEF_FOO
#undef FOO
#endif
yes it should work.
I have #pragma push_macro/pop_macro("macro_name") in mind, but it might work only in gcc and MS VC++
yes, it matters, you'll get a warning if it is defined again with a different value. As you state, you can shield it with #ifndef.