Killrazor
Killrazor

Reputation: 7184

Undefining functions using preprocessor macros

I've a log system written in C++ with this type of functions to write on it:

    void processMessages();
    void DEBUG_MSG(const std::string& appender,const char* msg, ...);
    void INFO_MSG(const std::string& appender,const char* msg, ...);
    void WARNING_MSG(const std::string& appender, const char* msg, ...);
    void ERROR_MSG(const std::string& appender, const char* msg, ...);
    void FATAL_MSG(const std::string& appender, const char* msg, ...);

I want to disable via macros in C++. I've read this thread: Disable functions using MACROS but

#ifdef GLOG_SILENCE
        #define processMessages     (void)sizeof
        #define DEBUG_MSG           (void)sizeof
        #define INFO_MSG            (void)sizeof
        #define WARNING_MSG         (void)sizeof
        #define ERROR_MSG           (void)sizeof
        #define FATAL_MSG           (void)sizeof
#else //GLOG_SILENCE
        void processMessages();
        void DEBUG_MSG(const std::string& appender,const char* msg, ...);
        void INFO_MSG(const std::string& appender,const char* msg, ...);
        void WARNING_MSG(const std::string& appender, const char* msg, ...);
        void ERROR_MSG(const std::string& appender, const char* msg, ...);
        void FATAL_MSG(const std::string& appender, const char* msg, ...);
#endif //GLOG_SILENCE

doesn't work properly. I keep getting errors like:

In file included from ../src/test_core.cpp:2:

../src/test_Log.h: In member function ‘virtual void LogTestFixtureTest_defining_SILENCE_macro_avoids_write_and_processing_activity_from_log_Test::TestBody()’:
../src/test_Log.h:63: error: expected unqualified-id before ‘(’ token
../src/test_Log.h:63: error: expected primary-expression before ‘void’
../src/test_Log.h:63: error: expected ‘;’ before ‘sizeof’
../src/test_Log.h:64: error: expected unqualified-id before ‘(’ token
../src/test_Log.h:64: error: expected primary-expression before ‘void’
../src/test_Log.h:64: error: expected ‘;’ before ‘sizeof’

I suspect that the problem is related with the fact that Log is a class, but I don't know how to do it. Some help?

Upvotes: 1

Views: 1494

Answers (3)

AlexTheo
AlexTheo

Reputation: 4184

I would like to suggest you to work in a different way. Just declare the interface ILogger after that implement it in the different loggers, like

class ILogger{
 public:
        virtual void DEBUG_MSG(const std::string& appender,const char* msg, ...);
        virtual  void INFO_MSG(const std::string& appender,const char* msg, ...);
        virtual  void WARNING_MSG(const std::string& appender, const char* msg, ...);
        virtual  void ERROR_MSG(const std::string& appender, const char* msg, ...);
        virtual  void FATAL_MSG(const std::string& appender, const char* msg, ...);
        virtual ~ILogger(){}
};

For the file logger

class FileLogger : public ILogger{
 public:
        void DEBUG_MSG(const std::string& appender,const char* msg, ...){....}
        void INFO_MSG(const std::string& appender,const char* msg, ...){....}
        void WARNING_MSG(const std::string& appender, const char* msg, ...){....}
        void ERROR_MSG(const std::string& appender, const char* msg, ...){....}
        void FATAL_MSG(const std::string& appender, const char* msg, ...){....}
        virtual ~EmptyLogger(){}
};

and the empty logger like:

for the empty logger

class EmptyLogger : public ILogger{
 public:
        void DEBUG_MSG(const std::string& appender,const char* msg, ...){do nothing here}
        void INFO_MSG(const std::string& appender,const char* msg, ...){do nothing here}
        void WARNING_MSG(const std::string& appender, const char* msg, ...){do nothing here}
        void ERROR_MSG(const std::string& appender, const char* msg, ...){do nothing here}
        void FATAL_MSG(const std::string& appender, const char* msg, ...){do nothing here}
        virtual ~FileLogger(){}
};

after that in the place where you create the logger could be a factory make a macros in order to generate a different type of logger.

class LoggerFactory{
public:
 static ILogger* getLogger(/*loggertype as argument*/){
   #ifdef GLOG_SILENCE
    /* create a normal logger*/
   #else
     return new EmptyLogger();
   #endif
 }
};

Upvotes: 0

Some programmer dude
Some programmer dude

Reputation: 409432

If your compiler support variadic macros you can simply define macros with empty replacements:

#ifdef GLOG_SILENCE
        #define processMessages(_1, _2, ...)
        #define DEBUG_MSG(_1, _2, ...)
        #define INFO_MSG(_1, _2, ...)
        #define WARNING_MSG(_1, _2, ...)
        #define ERROR_MSG(_1, _2, ...)
        #define FATAL_MSG(_1, _2, ...)
#else //GLOG_SILENCE
        void processMessages();
        void DEBUG_MSG(const std::string& appender,const char* msg, ...);
        void INFO_MSG(const std::string& appender,const char* msg, ...);
        void WARNING_MSG(const std::string& appender, const char* msg, ...);
        void ERROR_MSG(const std::string& appender, const char* msg, ...);
        void FATAL_MSG(const std::string& appender, const char* msg, ...);
#endif //GLOG_SILENCE

However, this will only work if the functions are NOT members of a class or a namespace, but true global functions.

Upvotes: 0

Mike Seymour
Mike Seymour

Reputation: 254701

Indeed, if these are member functions, then the "silent" versions will expand to nonsense:

log.(void)sizeof(stuff);

You could define a member function that does nothing, and macros that swallow their arguments:

void nothing() {}

#define processMessages(...) nothing()

then using the "silent" versions will give valid code that should compile away to nothing:

log.nothing();

The disadvantages of this are (a) you're relying on the compiler to inline the empty function, and not generate a function call; (b) the arguments' syntax is not checked when compiling in silent mode.

Upvotes: 4

Related Questions