-1

I'm trying to make a game debugger with limited warnings (if possible no warnings and suppressed warnings).

While creating a message interface class, I kept getting this warning: "Warning C4710 'IMessageA::IMessageA(IMessageType,size_t,const char *,...)': function not inlined Game Logger Game Logger\Source.cpp 256"

I know I could suppress the warning, but I would prefer to fix it then suppress it. I tried "__forceinline", "__inline", and "inline" but the compiler warning didn't go away.

enum class IMessageType
{
    IMessageType_Message,
    IMessageType_Info,
    IMessageType_Warning,
    IMessageType_Debug,
    IMessageType_Error,
    IMessageType_FatalError
};

enum class IMessageSource
{
    IMessageSource_None,
    IMessageSource_User,
    IMessageSource_Internal,
    IMessageSource_External,
    IMessageSource_Unknown
};

class IMessageA : public std::string
{
public:
    
    IMessageA(IMessageType Type, IMessageSource Source, const char* Caller, const char* File,
        const char* Func, int Line, size_t Words, const char* Format, ...)
    {
        _Type = Type;
        const char* MessageType = FormatMessageType(_Type);
        _Source = Source;
        const char* MessageSource = FormatMessageSource(_Source);
        _Caller = Caller;
        _File = File;
        _Func = Func;
        _Line = Line;
        time_t MessageTime = 0;
        time(&MessageTime);
        tm MessgeDateStamp = { 0 };
        localtime_s(&MessgeDateStamp, &MessageTime);
        char MessageTimeStamp[26] = { 0 };
        asctime_s(&MessageTimeStamp[0], 26, &MessgeDateStamp);
        std::unique_ptr<char[]> FormattedMessage = std::make_unique<char[]>(Words + 1);
        va_list _Args = nullptr;
        __crt_va_start(_Args, Format);
        _vsnprintf_s(FormattedMessage.get(), Words, Words, Format, _Args);
        _Args = nullptr;
        this->operator+=("[");
        this->operator+=(&MessageTimeStamp[0]);
        this->pop_back();
        this->operator+=("][");
        if (MessageSource != nullptr)
        {
            this->operator+=(&MessageSource[0]);
        }
        if (MessageSource != nullptr && _Caller != nullptr)
        {
            this->operator+=(": ");
        }
        if (_Caller != nullptr)
        {
            this->operator+=(_Caller);
            this->operator+=("][");
        }
        this->operator+=(MessageType);
        this->operator+=("] ");
        if (_Func != nullptr)
        {
            this->operator+=(_Func);
            this->operator+=(" - ");
        }
        if (_File != nullptr)
        {
            this->operator+=(_File);
            this->operator+=(": ");
        }
        if (_Line != 0)
        {
            this->operator+=("Line: ");
            this->operator+=(std::to_string(_Line));
            this->operator+=(" - ");
        }
        if (FormattedMessage != nullptr)
        {
            this->operator+=(FormattedMessage.get());
        }
        FormattedMessage.release();
    }
    IMessageA(IMessageType Type, size_t Words, const char* Format, ...)
    {
        _Type = Type;
        const char* MessageType = FormatMessageType(_Type);
        time_t MessageTime = 0;
        time(&MessageTime);
        tm MessgeDateStamp = { 0 };
        localtime_s(&MessgeDateStamp, &MessageTime);
        char MessageTimeStamp[26] = { 0 };
        asctime_s(&MessageTimeStamp[0], 26, &MessgeDateStamp);
        std::unique_ptr<char[]> FormattedMessage = std::make_unique<char[]>(Words + 1);
        va_list _Args = nullptr;
        __crt_va_start(_Args, Format);
        _vsnprintf_s(FormattedMessage.get(), Words, Words, Format, _Args);
        _Args = nullptr;
        this->operator+=("[");
        this->operator+=(&MessageTimeStamp[0]);
        this->pop_back();
        this->operator+=("][");
        this->operator+=(MessageType);
        this->operator+=("] ");
        if (FormattedMessage != nullptr)
        {
            this->operator+=(FormattedMessage.get());
        }
        FormattedMessage.release();
    }
private:
    _Check_return_ const char* FormatMessageType(IMessageType Type) noexcept
    {
        switch (Type)
        {
        case IMessageType::IMessageType_Message:
            return "_MSG_";
        case IMessageType::IMessageType_Info:
            return "_INFO";
        case IMessageType::IMessageType_Warning:
            return "_WARN";
        case IMessageType::IMessageType_Debug:
            return "DEBUG";
        case IMessageType::IMessageType_Error:
            return "ERROR";
        case IMessageType::IMessageType_FatalError:
            return "FATAL";
        }
        return "UKNWN";
    }
    _Check_return_ const char* FormatMessageSource(IMessageSource Source) noexcept
    {
        switch (Source)
        {
        case IMessageSource::IMessageSource_User:
            return "__USER__";
        case IMessageSource::IMessageSource_Internal:
            return "INTERNAL";
        case IMessageSource::IMessageSource_External:
            return "EXTERNAL";
        case IMessageSource::IMessageSource_Unknown:
            return "UNKNOWN_";
        case IMessageSource::IMessageSource_None:
            return nullptr;
        }
        return nullptr;
    }
protected:
    IMessageType _Type = IMessageType::IMessageType_Message;
    IMessageSource _Source = IMessageSource::IMessageSource_Internal;
    const char* _Caller = nullptr;
    const char* _File = nullptr;
    const char* _Func = nullptr;
    int _Line = 0;
    long _Reserved = 0;
};

Not sure if it's important, but I will include some extra data:

C++ Language Standard: ISO C++20 Standard (/std:c++20) C Language Standard: ISO C17 (2018) Standard (/std:c17) Warning Level: EnableAllWarnings (/Wall) Treat Warnings As Errors: Yes (/WX) And I set all of the C++ programmer rule sets to active to make sure I don't miss anything.

Sammy
  • 41
  • 8
  • 4
    Do not inherit `std::string`. Use it internally instead of inheritance. – Louis Go Feb 17 '22 at 01:41
  • 2
    See [why should not derive from STL](https://stackoverflow.com/a/6007040/4123703) and [why should not derive from string](https://stackoverflow.com/q/6006860/4123703). Also your code is not [mre]. – Louis Go Feb 17 '22 at 01:45
  • 2
    The [documentation for warning C4710](https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-4-c4710?view=msvc-170) points you to [a list of reasons why a function can become ineligible for inlining](https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-4-c4714?view=msvc-170), and one of the reasons matches your function: "Functions with a variable argument list." – Raymond Chen Feb 17 '22 at 01:47
  • So, my problem came from when I inherited std::string? – Sammy Feb 17 '22 at 01:53
  • 1
    It might not be the cause of warning, but it might be a design issue you may encounter later. Raymond's comment should might explain the issue. – Louis Go Feb 17 '22 at 01:57
  • 3
    typically you are asking for trouble by declaring your classes in a .cpp file rather than a .h file – pm100 Feb 17 '22 at 01:58
  • 1
    @pm100 well said. Although it doesn't always cause problems. –  Feb 17 '22 at 02:05
  • 1
    Sidenote: Identifiers starting with underscore followed by upper-case letter are reserved in all scopes. You are not allowed to use them as names. Underscore followed by some other character is ok as long as it is not at global namespace scope. – user17732522 Feb 17 '22 at 02:10

1 Answers1

4

It is because by current C++ standard, when you define member function body inside the class definition, it is equivalent to you are adding inline keyword to the function definition.

The compiler may ignore the inline keyword when it finds function definition is too big to inline.

It seems to me that the compiler you using prompts warning when the inline keyword is ignored. If you wish to supress the warning, separate the member function definition from its declaration.

K.R.Park
  • 1,015
  • 1
  • 4
  • 18
  • 1
    and looking at the code the compiler is probably correct - thats a lot of code to inline – pm100 Feb 17 '22 at 02:12
  • Good point. So, would it be best if I just suppress that warning? – Sammy Feb 17 '22 at 02:15
  • 1
    @Sammy Not only for the sake of supressing the warning, it is usually a good practice to separate the function declaration to the definition, as it hides the implementation detail from user, improving the security. Inlining should be utilized with caution. If you really need to optimize, use it selectively and limitedly. – K.R.Park Feb 17 '22 at 02:19
  • Thank you @K.R.Park. I have been doing that, but for right now I'm testing my code to make sure it works, so I'm putting it all in one file for the test and I will separate it later. I plan on making it a library for later use in my games. What warnings should I suppress for future reference? I try to limit my suppression to hopefully make my code more secure and stable. – Sammy Feb 17 '22 at 02:33
  • 1
    @Sammy Although it is better practice that you separate the code from the start, If you wish to do that way, just supressing compiler warning about `inline` can be a temporary solution. – K.R.Park Feb 17 '22 at 02:39
  • 1
    Thanks for the tip @K.R.Park. I will do that from now on. – Sammy Feb 17 '22 at 02:44
  • 1
    Also, when I did that, it fixed the warning. Thanks @K.R.Park. – Sammy Feb 17 '22 at 02:56