Reputation:
I recently acquired some code that I want to port to Linux. In a header file though, I have some curious code that I hope someone can shed some light on. Within a header file, inside a namespace where other classes are defined, I have the following:
#define CREATE_SINGLETON_METHODS(s) \
private: \
friend class Singleton<c>; \
##c(); \
virtual ~##c();
I understand that the ##
is the token pasting operation, but I can't figure out why the original author (who I don't know, and can't contact) used it. I have an implementation class that looks like this:
class MapManager : public Singleton<MapManager> {
CREATE_SINGLETON_METHODS(MapManager)
private:
...
When I compile, I get the following error:
error: pasting ";" and "MapManager" does not give a valid preprocessing token
This compiles find on Windows and some earlier versions of gcc (pre 4.x). Any ideas as to what could be going on here? Thanks!
Upvotes: 3
Views: 1679
Reputation: 433
I had a similar problem sometime ago. Try running:
g++ -E mytestfile.h
(using your own filename of course) on the command line to see what the results of the preprocessor are. It may help show what is going on. I am running gcc 3.4.4 and get the same errors you describe as happening only in 4.x (though the code works fine in Visual Studio 2008).
Eliminating the tokenizers will fix the problem:
#define CREATE_SINGLETON_METHODS(c) \
private: \
friend class Singleton<c>; \
c(); \
virtual ~c();
This code gives me the following as a preprocessor result (copied from my command line with the -E option):
private: friend class Singleton<MapManager>; MapManager(); virtual ~MapManager();
which the compiler is happy with.
According to http://gcc.gnu.org/onlinedocs/gcc-4.0.4/cpp/Tokenization.html:
Once the input file is broken into tokens, the token boundaries never change, except when the `##' preprocessing operator is used to paste tokens together. The compiler does not re-tokenize the preprocessor's output. Each preprocessing token becomes one compiler token.
'##' breaks the tokenization rules in this case. Per the error your getting, the preprocessor most likely gave the compiler a token set with ";MapManager()" in it, which the 4.x compiler obviously doesn't like.
And some information form here (http://gcc.gnu.org/onlinedocs/cpp/Concatenation.html#Concatenation) is also worth noting:
It is common to find unnecessary uses of '##' in complex macros. If you get this warning, it is likely that you can simply remove the '##'.
Hope that helps.
Upvotes: 1
Reputation: 340168
The preprocessor operators for 'stringizing' and token pasting ('#
' and '##
') can only be reliably used on macro parameters. Also, you generally need to use a level of indirection to get them to work in all cases (particularly when using them with things that are themselves macros).
See
for some additional details.
Upvotes: 1
Reputation: 123
I use my own generic singleton template: Try replacing those icky macros with this template:
#ifndef SINGLETON_HPP_STYLET
#define SINGLETON_HPP_STYLET 0
/*
*
*
* Generic Singleton implementation
*
*
*/
template <class T>
class SingletonHolder : public T
{
public:
static SingletonHolder<T>& getInstance()
{
static SingletonHolder<T> instance;
return instance;
}
private:
SingletonHolder()
{
};
virtual ~SingletonHolder()
{
};
};//class SingletonHolder
#endif //SINGLETON_HPP_STYLET
//------------------------------------------------------------------
USAGE:
class SomeClass;
typedef SingletonHolder<SomeClass> SomeClassSingleton;
SomeClassSingleton::getInstance().doSomething();
Upvotes: 2
Reputation: 9333
Try changing the macro to this:
#define CREATE_SINGLETON_METHODS(c) \
private: \
friend class Singleton<c>; \
c(); // Note the change on this line! \
virtual ~##c();
I took out one of the ## operators. Looks like ";" was being merged with "c();" in gcc 4.
Upvotes: 1
Reputation: 6080
I always find that this kind of preprocessor "magic" (read garbage) creates more trouble than it's worth. In some cases it's a necessary evil but I don't think that applies here. I'd rewrite any instances of it in the code and eliminate that hideous thing.
Upvotes: 1
Reputation: 132978
How on earth did you get this to compile at any compiler? First of all it should probably be:
#define CREATE_SINGLETON_METHODS(c) \
private: \
friend class Singleton<c>; \
##c(); \
virtual ~##c();
Since I assume it's the macro parameter that is defining the friend class, a private constructor and a private destructor.
Upvotes: 0
Reputation: 13521
Looks to me like the ## before the constructor isn't useful. The one on the destructor is meant to paste the tilde to the typename. Perhaps the original author copy-and-pasted, and didn't get a compile error, because it is an older version, so didn't catch the error.
Upvotes: 1
Reputation: 67739
It looks like a poorly-done attempt at automatic singleton creation. In general this is possible to do without macros if you can put up with a virtual function or virtual inheritance with some clever template tricks.
If I were you, I would just manually rewrite the related code for the classes affected. Macros are bad news for stuff like this.
Upvotes: -1