Search code examples
c++variadic-templatesvariadic-functions

Execute a statement once in a variadic function call


I have a following Log class in order to output useful information:

class Log
{
public:
    enum {ALL = 0, DEBUG, ERROR};

    static void setDebugMode()
    {
        mDebugMode = true;
    }

    template <class T, class ... Args>
    static void write(unsigned int level, T&& arg, Args&& ... args)
    {
        switch (level)
        {
        //Important piece of information that needs to be displayed
        case ALL:
        {
            std::cout << std::forward<T>(arg);
            write(level, out, std::forward<Args>(args) ...);
            break;
        }
        //For reporting errors
        case ERROR:
        {
            std::cerr << std::forward<T>(arg);
            write(level, out, std::forward<Args>(args) ...);
            break;
        }
        //Additional information that is available in debug mode
        case DEBUG:
        {
            if(!mDebugMode)
                break; //If debug mode not set, get out

            std::cout << std::forward<T>(arg);
            write(level, out, std::forward<Args>(args) ...);
            break;
        }
        }
    }
    template <class T>
    static void write(unsigned int level, T&& t)
    {
        switch(level)
        {
        case ALL:
        {
            std::cout << std::forward<T>(t) << std::endl;
            break;
        }
        case DEBUG:
        {
            std::cout << std::forward<T>(t) << std::endl;
            break;
        }
        case ERROR:
        {
            std::cerr << std::forward<T>(t) << std::endl;
            break;
        }
        }
    }

private:
    Log();
    static bool mDebugMode;
};

My Question is the following: How can I output "(DEBUG)" once to the console without it getting printed each function call? That is I want to get the following output if I use the write function with DEBUG passed in as the level:

(DEBUG) 13852 files loaded

Solution

  • You can both simplify your code and make this prefix easy by using fold expressions instead of a recursive implementation. (Fold expressions require a C++17 compiler / compiler mode.)

    // The only write function needed:
    template <class ... Args>
    static void write(unsigned int level, Args&& ... args)
    {
        switch (level)
        {
        //Important piece of information that needs to be displayed
        case ALL:
        {
            (std::cout << ... << std::forward<Args>(args));
            break;
        }
        //For reporting errors
        case ERROR:
        {
            (std::cerr << ... << std::forward<Args>(args));
            break;
        }
        //Additional information that is available in debug mode
        case DEBUG:
        {
            if(!mDebugMode)
                break; //If debug mode not set, get out
    
            std::cout << "(DEBUG) ";
            (std::cout << ... << std::forward<Args>(args));
            break;
        }
        }
    }