See following code:
#include <print>
#include <exception>
#include <string>
#include <format>
class exception_t
: public std::exception
{
public:
template<class... args_t>
exception_t(std::string_view users_fmt, args_t&&... args)
: m_users_fmt(users_fmt)
, m_format_args(std::move(std::make_format_args(args...)))
{}
char const* what() const noexcept override
{
thread_local static std::string s = std::vformat(m_users_fmt, m_format_args);
return s.c_str();
}
private:
std::string m_users_fmt;
std::format_args m_format_args;
};
int main()
try
{
throw exception_t("{}", 42);
}
catch (std::exception& e)
{
std::println("{}", e.what());
}
When debugging this under MSVC 2022 v143 with SDK 10.0.19041.0, I see that during the construction of exception_t m_format_args has an appropriate value, but at the time of calling what(), m_format_args has an invalid value. Most likely this is a lifetime issue, but I cannot see what is going wrong. (Most often this program does not print 42)
What am I doing wrong here?
=================================================
Update after response of HolyBlackCat
Above is a minimal code snippet, but it is the intention to completely separate the formatting from exception/error/warning reporting. I'd like to store a standard type with the arguments e.g. on disk. And later another process reads it from disk and displays the data using a format string of the local language. That's why I don't want to call std::vformat in the constructor in this code snippet.
Does any alternative for std::format_args exist? E.g. can I store args?
I found a way to store args and get the program working. I needed to add the types variant_t and variants_t and define a user defined formatter. Then the above code snippet needs only a few small changes:
It is not completely ideal:
The definitions of variant_t, variants_t and the user defined formatter is as follows: