Search code examples
c++templatesoperator-overloadingmisra

MISRA warning when overriding bitwise operator


I wrote a simple wrapper for the logging interface, so I can use left-shift operator<< to print log.

logger_wrapper.h

class LoggerWrapper
{
public:

    LoggerWrapper(logging::LoggerInterface *logger, logging::LogPriority priority);

    ~LoggerWrapper();

    bool log_enabled();

    std::stringstream& get_stream();

private:

    std::stringstream stream_;

    logging::LoggerInterface *logger_;

    logging::LogPriority priority_;
};


template <typename T>
LoggerWrapper& operator<<(LoggerWrapper& record, T&& t) {
    if (record.log_enabled())
    {
        record.get_stream() << std::forward<T>(t);
    }
    return record;
}

template <typename T>
LoggerWrapper& operator<<(LoggerWrapper&& record, T&& t)
{
    return record << std::forward<T>(t);
}

logger_wrapper.cpp

#include "logger_wrapper.h"


LoggerWrapper::LoggerWrapper(logging::LoggerInterface *logger, logging::LogPriority priority)
    : logger_{ logger }
    , priority_ { priority }
{

}

bool LoggerWrapper::log_enabled()
{
    return (nullptr != logger_) && (logger_->isLogPriorityEnable(priority_));
}

std::stringstream& LoggerWrapper::get_stream()
{
    return stream_;
}

LoggerWrapper::~LoggerWrapper()
{
    if (log_enabled())
    {
        logger_->log(priority_, stream_.str());
    }
}

The code was compiled successfully, but I had some MISRA warning:

M5.17.1 (required): Missing overload for corresponding assignment version of operator (operator<<<basic_string&>())
M5.17.1 (required): Missing overload for corresponding assignment version of operator (operator<<<basic_string<char,char_traits<char>,allocator<char>>>())
M5.17.1 (required): Missing overload for corresponding assignment version of operator (operator<<<const atomic&>())
M5.17.1 (required): Missing overload for corresponding assignment version of operator (operator<<<const basic_string&>())
M5.17.1 (required): Missing overload for corresponding assignment version of operator (operator<<<const char (&)[10]>())
...

According to MISRA C++ 2008, Rule M-5-17-1 states that:

The semantic equivalence between a binary operator and its assignment operator form shall be preserved.

I hope someone can explain me what the warnings mean and what I should do to remove it. Any reply is greatly appreciated. Thank you.


Solution

  • The MISRA guideline essentially says that "For any binary operator (call it @), if you overload operator@() for your class then also overload the operator@=(), and ensure they behave consistently". The purpose is to ensure that (where x is an instance of your class).

     x = x @ y;    //  @ may represent +, - , <<, *, /, .....
    

    has the same net effect as (i.e. is consistent with).

    x @= y;
    

    In your case, your class has (templated) overloads of operator<<() but no corresponding overloads of operator<<=().

    One way to stop the warnings is to provide corresponding overloads of operator<<=() whenever you provide an operator<<() (or vice versa).

    For example, provide a operator<<=()

    template <typename T>
    LoggerWrapper& operator<<=(LoggerWrapper& record, T&& t)
    {
        if (record.log_enabled())
        {
            record.get_stream() << std::forward<T>(t);
        }
        return record;
    }
    

    and (to ensure the required consistency), use the approach of defining the operator<<() so it calls the operator<<=().

    template <typename T>
    LoggerWrapper& operator<<(LoggerWrapper& record, T&& t)
    {
         return operator<<=(record, t);
    }