I came across this code that involved variadic Macros and I wanted to know what that meant
#define DECLARE_LEGACY_TYPES(...) //This all of the macro - I am not holding out on anything
Now There is this class as this
Header file: .h
namespace LG_Wrapper
{
template <LG_Thread Thread>
class EffectApplication : public ktApplication
{
public:
static EffectApplication<Thread>& GetInstance();
protected:
.....
.....
static boost::recursive_mutex mResource;
}
}
DECLARE_LEGACY_TYPES(EffectApplication); <---- What does this do ?
I wanted to know what effect the macro has ?
Update:
I have received numerous downvotes on this as this question gives of the impression that something is missing that I did not post the entire content of the macro. There is nothing more to the macro. I wish there was. This question is related to this which was closed. The macro literally just ends after (...)
#define DECLARE_LEGACY_TYPES(...)
but there isnt. That is one of the reason why I am here as I am not sure how to deal with this situation. Does this macro have not effect then ?
More Info:
This is what I have in another file
I am using the following defined in my project setting
LG_WRAPPER_EXPORTS
LG_THREAD_NAME=GAME
Following is the code
namespace LG_Wrapper
{
enum LG_Thread
{
GAME,
OTHER
};
/*
If the library itself is including this file
*/
#ifdef LG_WRAPPER_EXPORTS
#ifndef LG_THREAD_NAME
#error You must define LG_THREAD_NAME!
#endif
//Legacy types should not be used internally
#define DECLARE_LEGACY_TYPES(...)
#else // LG_WRAPPER_EXPORTS
//Legacy typenames are provided for convenience to the client
#define DECLARE_LEGACY_TYPES(ClassType) \
typedef LG_Wrapper::##ClassType##<LG_Wrapper::GAME> ClassType; \
#endif // LG_WRAPPER_EXPORTS
}
This is actually pretty common, but it depends on other code that wasn't mentioned in the other code you looked at:
#if USING_OLD_COMPILER //when using an older compiler, use this to declare legacy types
#define DECLARE_LEGACY_TYPES(...) STUFF(__VA_ARGS__)
#else //new compiler doesn't have to do anything special
#define DECLARE_LEGACY_TYPES(...)
#endif
//in older compilers we had to declare legacy types for this
//newer compilers don't need this step, so this does nothing at all in them.
DECLARE_LEGACY_TYPES(EffectApplication);
I don't actually know this macro, so I don't know it's actual purpose. But it's common to see macros without definitions for similar tricks as this.
Related
I was going through this code (line 41):
https://github.com/black-sat/black/blob/master/src/lib/include/black/logic/parser.hpp
and came across something like this:
#include <iostream>
#define YES
class YES myClass{};
int main(){
cout << "Hi\n";
return 0;
}
What is the purpose of defining a macro and using it in front of a class identifier?
The way you've written it there isn't much point. But if you look at the project's common.hpp file to see how it's used, it makes a lot of sense, and is a common pattern in C and C++:
#ifdef _MSC_VER
#define BLACK_EXPORT __declspec(dllexport)
#else
#define BLACK_EXPORT
#endif
...
class BLACK_EXPORT parser
{
public:
...
Here the author has defined compiler-dependent attributes. If the code is built using MSVC, then any class marked with the BLACK_EXPORT macro will get the dllexport attribute. For other compilers it will do nothing.
If you see, for example:
https://en.cppreference.com/w/cpp/language/class
you'll see that there are a lot of modifiers for a class (for instance, look into the attr optional parameter here: https://en.cppreference.com/w/cpp/language/attributes).
Defining that macro with the required values can adapt the class as required whenever it is included.
I'm using an external C library inside a C++ project.
The header contains a struct with a variable named class:
#ifdef __cplusplus
extern "C" {
#endif
struct something_t {
...
sometype class;
};
#ifdef __cplusplus
}
#endif
g++ does not like this and complains about "error: expected identifier before ';' token".
What options do I have?
I could rename class, but that's cumbersome and breaks upstream compatibility.
I could ask the upstream project to rename the variable, but that may be difficult.
I could redefine class in the header using the preprocessor: #define class class_ Are there any side effects?
Any other suggestions?
What's the best way to handle this situation?
Result: Based on the prevailing preference for option 2, I finally chose to initiate a renaming in the upstream library.
As others already mentioned in comments, the best option is to write another C API layer around that stuff, that uses the other API only internally.
Anything related to this offending struct definition should be exported through opaque pointers only.
In C++ you can use the cleaned up C-API then.
Here's a small sketch:
ThirdParty.h (contains offending code to compile with c++)
#ifdef __cplusplus
extern "C" {
#endif
struct something_t {
...
sometype class;
};
struct something_t* CreateSomething(); // Does memory allocation and initialization
void DoSomething(struct something_t* something);
#ifdef __cplusplus
}
#endif
MyApiWrapper.h
#ifdef __cplusplus
extern "C" {
#endif
typedef void* psomething_t;
struct psomething_t MyCreateSomething(); // Does memory allocation and initialization
void MyDoSomething(psomething_t something);
#ifdef __cplusplus
}
#endif
MyApiWrapper.c
#include "ThirdParty.h"
struct psomething_t MyCreateSomething() {
psomething_t psomething = (psomething_t)CreateSomething();
return psomething;
}
void MyDoSomething(psomething_t something) {
DoSomething((struct something_t*)psomething);
}
Regarding your considered solutions
I could ask the upstream project to rename the variable, but that may be difficult
You certainly should report that bug to let them know. If it's a git-hub hosted project prepare a pull request.
Anyways be prepared that they might not be responsive timely, and you should always have the above mentioned "plan B". It will work regardless ...
I could redefine class in the header using the preprocessor: #define class class_ Are there any side effects?
It could be a viable way, if any place where this particular symbol (class) appears is plain c code and no other parts of the 3rd party c code (e.g. as library) depends on that symbol (which is unlikely).
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.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
I know the basic rules, use inline, enum and const instead of #define, that is not what I'm after with this question. What I want to know is what is considered an acceptable scenario in which you would use a #define macro, and how, in C++.
Please do not post question or links to "define vs const" questions or "preprocessor vs compiler", and I've already gone through Effective C++ by Scott Meyers and I know the advantages of one over the other.
However after hours and hours of surfing the net, I get the feeling #define is treated as some kind of underdog in C++, but I'm sure there must be a case in which it could be acceptable, even desirable, to use it.
To get the ball rolling I guess one scenario I could think of is to create a DEBUG macro that based on it enables prints and whatnot all over the code for debug purposes.
Here are a few scenarios where using #define is a good solution:
Adding diagnostics information while preserving function signature:
#ifdef _DEBUG
#define Log(MSG) Log((MSG), __FILE__, __LINE__);
#endif
Conditional compilation and include guards are also a good example (no example given, as you should understand this :)).
Boilerplate code is another example, but this can easily be abused. A good example of using macros for boilerplate code is the BOOST_AUTO_TEST_CASE macro in Boost.UnitTest (a worse example is the WinAPI macro set that maps Windows APIs to their CHAR or WCHAR macros).
Another good example is providing compiler-specific keywords and settings:
#if (defined _WIN32) && (defined LIB_SHARED)
# ifdef LIB_EXPORTS
# define LIB_EXPORT __declspec(dllexport)
# else
# define LIB_EXPORT __declspec(dllimport)
# endif /* LIB_EXPORTS */
#else
# define LIB_EXPORT extern
#endif /* _WIN32 && LIB_SHARED */
Usage:
// forward declaration of API function:
LIB_EXPORT void MyFunction(int);
The simple setup for debug/release or for crossplatform code. Here is a sample of my program:
void Painter::render()
{
if (m_needsSorting)
{
_sort();
}
for (GameObject* o : m_objects)
{
o->render();
#ifdef _DEBUG
o->renderDebug();
#endif
}
}
and one more for win/ios:
#ifdef _WIN32
#include "EGL/egl.h"
#include "GLES2/gl2.h"
#include <Windows.h>
#ifdef _ANALYZE
#include <vld.h>
#endif
#else // IOS
#import <Availability.h>
#import <UIKit/UIKit.h>
#import <GLKit/GLKit.h>
#import <Foundation/Foundation.h>
#endif
the other thing is for libraries:
#ifdef VECTRY_INLINE
#define vinline inline
#else
#define vinline
#endif
and some useful stuff like this:
#define MakeShared(T) \
class T; \
typedef shared_ptr<T> T##Ptr
Sometimes, you want to generate code without having to repeat the neverending boilerplate, or without having to use another language to do so. From time to time, templates will not be not enough, and you will end up using Boost.Preprocessor to generate your code.
One example where macros are "required" is Boost.TTI (type traits introspection). The underlying mechanism somehow abuses the language to create a couple of powerful metafunctions, but needs great amounts of boilerplate. For example, the macro BOOST_TTI_HAS_MEMBER_FUNCTION generates a matefunction that checks whether a class has a given member function. Doing so requires to create a new class and cannot be short without a macro (examples of non-macro solutions to tackle the problem here).
There are also some times when you will need to use X-macros to generate your code. It is pretty useful to bind things at compile time. I am not sure whether they can be totally replaced or not as of today, but anyway, you can find some really interesting examples of applications here.
To sum up, macros can be a powerful tool to generate code, but they need to be used with caution.
One of the few usefull cases in C++ are include guards:
// A.h
#ifndef _A_H_
#define _A_H_
class A
{ /* ... */ };
#endif /* _A_H_ */
I think when C was introduced then C didn't use to have consts, so #defines were the only way of providing constant values. But later on #define was not much used since consts took the place(or in better words we can say that consts were more readily used). But I would say include guards is still one area where they are used. And they are used since your code is more readable.
Header inclusion guards is one area where you cannot use consts
And example:
#ifndef GRANDFATHER_H
#define GRANDFATHER_H
struct foo {
int member;
};
#endif /* GRANDFATHER_H */
You may also check Why would someone use #define to define constants?
One more thing to add that #defines don't respect scopes so there is no way to create a class scoped namespacewhereas const variables can be scoped in classes.(I know you know the difference but thought to add it as it is important.)
Also to show one example where #define is used:
static double elapsed()
{ ... }
#define ELAPSED '[' << std::fixed << std::setprecision(2) << elapsed() << "] "
// usage:
for (vector<string>::iterator f = files.begin(); f != files.end(); f++) {
cout << ELAPSED << "reading file: " << *f << '\n';
process_file(*f);
}
Using Doxygen, I stumbled across this warning:
D:/<some/path>/Camera.h:20: warning: documented symbol `enum DLLPORT
ct::CameraCapture::ct::CameraCapture::CamType' was not declared or defined.
Now I know why Doxygen does not find that class (the namespaces are obviously duplicated), what I don't understand is why it is even searching for it. This enum is in a header file, directly above a class definition, and the class is found fine, it also doesn't get those double namespaces generated.
The source code compiles, too, so it probably isn't a syntactic error that is causing Doxygen these problems.
Specifically, the source code looks like this:
#ifdef CT_EXPORTS
#define DLLPORT __declspec(dllexport)
#else
#define DLLPORT __declspec(dllimport)
#endif
#include <somelibrary>
namespace ct {
namespace CameraCapture {
/**The type of camera used:
*[...]
**/
enum DLLPORT CamType {
CT_ENUM1=0,
CT_ENUM2,
CT_ENUM3,
CT_NONE
};
/**\brief A parent-class to cameras of all types.
*[...]
**/
class DLLPORT Camera
{
//...some content...
};
}
}
This same problem occurs with other enum blocks, too.
Hopefully some of you guys know what is happening there.
Cheers
You don't need to dllexport nor dllimport enums. They're mere declarations of a type, not of code. Just use enum CamType. Classes (either en'masse or by-member) will need it, as will individual free functions, but simple enums do NOT.