fix ADL lookup error for to_string()-ing user-defined classes

fmt::to_string: use fmt::format() instead of format(), because otherwise unrelated free-standing format() function
from the printed class namespace could be called. Example of the bug here: https://stackoverflow.com/q/62423981/19905

This commit includes a test as well.

Applied against 6.2.1 because current fmt version seems to be broken at the
moment for fmt::to_string()-ing user-defined classes.
This commit is contained in:
Anton Voloshin 2020-06-19 15:34:12 +03:00
parent 19bd751020
commit e8b47c3efb
No known key found for this signature in database
GPG Key ID: EACB7E6EF3F03D8D
2 changed files with 24 additions and 2 deletions

View File

@ -3336,14 +3336,14 @@ arg_join<internal::iterator_t<const Range>, wchar_t> join(const Range& range,
\endrst
*/
template <typename T> inline std::string to_string(const T& value) {
return format("{}", value);
return fmt::format("{}", value);
}
/**
Converts *value* to ``std::wstring`` using the default format for type *T*.
*/
template <typename T> inline std::wstring to_wstring(const T& value) {
return format(L"{}", value);
return fmt::format(L"{}", value);
}
template <typename Char, std::size_t SIZE>

View File

@ -2043,9 +2043,31 @@ TEST(FormatTest, DynamicFormatter) {
"precision not allowed for this argument type");
}
namespace unrelated {
struct qwe{};
std::string format(const char * /*fmt*/, const qwe &) {
// Return distinct string on purpose to check whether fmt used
// this format() via ADL by mistake
return "{unrelated free-standing format() function discovered by ADL by mistake}";
}
} // namespace unrelated
template<>
struct fmt::formatter<unrelated::qwe> {
template<typename ParseContext>
auto parse(ParseContext & ctx) -> decltype(ctx.begin()) { return ctx.begin(); }
template<typename FormatContext>
auto format(const unrelated::qwe &, FormatContext & ctx) -> decltype(ctx.out()) {
return fmt::format_to(ctx.out(), "[qwe]");
}
};
TEST(FormatTest, ToString) {
EXPECT_EQ("42", fmt::to_string(42));
EXPECT_EQ("0x1234", fmt::to_string(reinterpret_cast<void*>(0x1234)));
EXPECT_EQ("[qwe]", fmt::to_string(unrelated::qwe{}));
}
TEST(FormatTest, ToWString) { EXPECT_EQ(L"42", fmt::to_wstring(42)); }