I'm writing a Win32Exception for an application I'm working on, the header file looks like this:
class Win32Exception : std::exception {
public:
    Win32Exception() = default;
    explicit Win32Exception(const std::wstring& message);
    explicit Win32Exception(const std::string& message);
    explicit Win32Exception(const char* message);
    virtual ~Win32Exception() throw() override = default;
    char const* what() const override;
    std::wstring message() const;
};
The implementation for the what function looks like this:
char const* Win32Exception::what() const
{
    DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER;
    DWORD errorCode = GetLastError();
    DWORD systemLocale = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
    LPSTR buffer = nullptr;
    DWORD length = FormatMessageA(flags, nullptr, errorCode, systemLocale, (LPSTR)&buffer, 0, nullptr);
    if(buffer != nullptr)
    {
        LocalFree(buffer);
    }
    else if (length == 0)
    {
        buffer = "Cannot get an error message. FormatMessage failed.";
    }
    return buffer;
}
The implementation for the message function looks like this:
std::wstring Win32Exception::message() const
{
    DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER;
    DWORD errorCode = GetLastError();
    DWORD systemLocale = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
    LPWSTR buffer = nullptr;
    DWORD length = FormatMessageW(flags, nullptr, errorCode, systemLocale, (LPWSTR)&buffer, 0, nullptr);
    if (buffer != nullptr)
    {
        LocalFree(buffer);
    }
    else if (length == 0)
    {
        buffer = L"Cannot get an error message. FormatMessage failed.";
    }
    return buffer;
}
Now, I would like to get rid of this duplication so I thought I can do something about it with a template, like this:
    template <typename TResult, DWORD (*formatMessageVersion)(DWORD, LPCVOID, DWORD, DWORD, TResult, DWORD, va_list*)>
TResult formatMessage(DWORD& systemLocale, DWORD& errorCode, TResult& fallbackMessage) const {
    DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER;
    TResult buffer = nullptr;
    DWORD length = formatMessageVersion(flags, nullptr, errorCode, systemLocale, (TResult)&buffer, 0, nullptr);
    if (buffer != nullptr)
    {
        LocalFree(buffer);
    }
    else if (length == 0)
    {
        buffer = fallbackMessage;
    }
    return buffer;
}
In one of my attempts I tried to pass the function FormatMessageA/W as an argument to formatMessage through std::function but I'm not sure why it didn't work...
The way I thought I to use this is as follow:
char const* Win32Exception::what() const
{
    DWORD errorCode = GetLastError();
    DWORD systemLocale = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
    return formatMessage<LPSTR, FormatMessageA>(systemLocale,
                                                errorCode,
                                                "Cannot get an error message. FormatMessage failed.");
}
std::wstring Win32Exception::message() const
{
    DWORD errorCode = GetLastError();
    DWORD systemLocale = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
    return formatMessage<LPWSTR, FormatMessageW>(systemLocale,
                                                errorCode,
                                                L"Cannot get an error message. FormatMessage failed.");
}
But I'm getting bunch of errors:
Severity    Code    Description Project File    Line    Suppression State
Error   C2664   'TResult Yalla::Win32Exception::formatMessage<LPSTR,DWORD FormatMessageA(DWORD,LPCVOID,DWORD,DWORD,LPSTR,DWORD,va_list *)>(DWORD &,DWORD &,TResult &) const': cannot convert argument 3 from 'const char [51]' to 'LPSTR &' RunBox  d:\users\eyal\projects\code\yalla\core\src\runbox\win32\win32-exception.cpp 29  
Severity    Code    Description Project File    Line    Suppression State
Error   C2664   'TResult Yalla::Win32Exception::formatMessage<LPSTR,DWORD FormatMessageA(DWORD,LPCVOID,DWORD,DWORD,LPSTR,DWORD,va_list *)>(DWORD &,DWORD &,TResult &) const': cannot convert argument 3 from 'const char [51]' to 'LPSTR &' RunBox  d:\users\eyal\projects\code\yalla\core\src\runbox\win32\win32-exception.cpp 29  
Severity    Code    Description Project File    Line    Suppression State
Error   C2664   'TResult Yalla::Win32Exception::formatMessage<LPWSTR,DWORD FormatMessageW(DWORD,LPCVOID,DWORD,DWORD,LPWSTR,DWORD,va_list *)>(DWORD &,DWORD &,TResult &) const': cannot convert argument 3 from 'const wchar_t [51]' to 'LPWSTR &'   RunBox  d:\users\eyal\projects\code\yalla\core\src\runbox\win32\win32-exception.cpp 40  
Severity    Code    Description Project File    Line    Suppression State
Error   C2664   'TResult Yalla::Win32Exception::formatMessage<LPWSTR,DWORD FormatMessageW(DWORD,LPCVOID,DWORD,DWORD,LPWSTR,DWORD,va_list *)>(DWORD &,DWORD &,TResult &) const': cannot convert argument 3 from 'const wchar_t [51]' to 'LPWSTR &'   RunBox  d:\users\eyal\projects\code\yalla\core\src\runbox\win32\win32-exception.cpp 40  
Severity    Code    Description Project File    Line    Suppression State
Error (active)      no instance of function template "Yalla::Win32Exception::formatMessage" matches the argument list   RunBox  d:\Users\Eyal\Projects\Code\Yalla\core\src\runbox\win32\win32-exception.cpp 27  
Severity    Code    Description Project File    Line    Suppression State
Error (active)      no instance of function template "Yalla::Win32Exception::formatMessage" matches the argument list   RunBox  d:\Users\Eyal\Projects\Code\Yalla\core\src\runbox\win32\win32-exception.cpp 38  
Bear in my mind that I'm relearning C++ and didn't touch it for many years so if you can tell me how to improve the code or do whatever that I'm trying to do in a better way, I'd be really glad to hear about it! ;)
Update: You can find the final solution at GitHub, thanks to everyone.
 
     
     
    