In an attempt to refactor this code:
static const auto opf_str = [&]() {
std::string result;
for(auto& e : extension_list) {
result.append(StringUtils::ToUpperCase(e.substr(1)) + " file (*"s + e + ")\0*"s + e + "\0"s);
}
result += "All Files (*.*)\0*.*\0\0"s;
return result;
}();
I replaced the std::string::operator+
joins with std::format
:
static const auto opf_str = [&]() {
std::string result;
for(auto e : extension_list) {
result.append(std::format("{0} file (*{1})\0*{1}\0", StringUtils::ToUpperCase(e.substr(1)), e));
}
result += "All Files (*.*)\0*.*\0\0"s;
return result;
}();
But the internal null characters (which are required for how OPENFILENAME
works) are being stripped in the std::format
version.
Changing the format string to an actual std::string
causes a compiler error because the string isn't a compile-time constant.
std::string
as argument doesn't work, but at least std::string_view
should be fine. There is no issue with having it even as the result of a constant expression if it is referencing only static objects:
std::format("{0} file (*{1})\0*{1}\0"sv, StringUtils::ToUpperCase(e.substr(1)), e)
Looking a the current draft specification of std::basic_format_string
it is indeed impossible to use a std::string
as format string to std::format
, even if its construction is a constant expression. As an alternative it is of course always possible to use std::vformat
instead, which doesn't perform the compile-time checks. (It is in the end not really surprising since the consteval
construction of the std::basic_format_string
would need to copy the string contents, but can't rely on storing the result in dynamic memory.)