vendredi 4 décembre 2020

template class with logger policy to enable or disable logging at compile time

There are various ways to enable or disable logging at compile time. The most basic is to use preprocessor definitions and macros.

DEBUG("Debug message shown only when building debug");

Core guidelines state that you should avoid using macros whenever possible, because they are not a part of C++ language. When using DEBUG macros, a global logger object should be used, which restricts you from changing the destination output at some extent.

Another way, which is implemented using the language itself is via virtual methods and abstract logger types. For instance, std::basic_ostream<Char>' can be passed by pointer to the *loggable* object or function, so the latter can invoke its operator<<if it is notnullptr`:

void foo(std::basic_ostream *logger)
{
    if (logger)
        (*logger) << "logging...";
}

This approach is customizable: you can log to console, or file, or socket, etc.

But this does compile additional code and checks. I thought of using a template policy parameter for a logger, that will not compile any logging code if, for example, a void_logger has been provided.

Here is my attempt, I have some problems compiling this code with std::enable_if for default constructor:


struct void_logger
    {
    };

    template<typename T>
    constexpr void_logger &operator<<(void_logger &voidLogger, T)
    {
        return voidLogger;
    }

template<typename Logger>
class loggable
{
public:
    using logger_type = typename std::conditional<
            std::is_same<Logger, void_logger>::value,
            Logger,
            Logger &>::type;

    // this fails
//    template<typename = typename
//    std::enable_if<std::is_same<Logger, void_logger>::value>::type>
//    constexpr loggable()
//            : logger_(logger_type())
//    {}

    constexpr loggable(logger_type logger)
            : logger_(logger)
    {}

protected:
    logger_type logger_;
};

struct Foo : loggable<std::ostream>
{
    Foo()
            : loggable<std::ostream>(std::cout)
    {}

    void bar()
    {
        logger_ << "Logging\n";
    }
};


int main()
{
    Foo foo;
    foo.bar();

    return 0;
}

What can I do to solve the error?

“enable_if cannot be used to disable this declaration”

Should I not use a reference and use a pointer for a logger object?

Aucun commentaire:

Enregistrer un commentaire