From 0e601c34de26fe5b46f4c62dab2039efcb0acaed Mon Sep 17 00:00:00 2001 From: Yat Ho Date: Fri, 26 Jun 2026 03:21:59 +0800 Subject: [PATCH] fix: explicitly check `operator[]` in `is_contiguous` (#4825) Prevent false positives when the container itself does not have `operator[](size_t)`, but the target type of one of the non-explicit user-defined conversion functions does. --- include/fmt/base.h | 7 ++++--- test/base-test.cc | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/include/fmt/base.h b/include/fmt/base.h index 5d0241c8..60d1b792 100644 --- a/include/fmt/base.h +++ b/include/fmt/base.h @@ -493,9 +493,10 @@ inline FMT_CONSTEXPR auto get_container(OutputIt it) -> template struct is_contiguous : std::false_type {}; template -struct is_contiguous().data()), - decltype(std::declval().size()), - decltype(std::declval()[size_t()])>> +struct is_contiguous().data()), + decltype(std::declval().size()), + decltype(std::declval().operator[](size_t()))>> : std::true_type {}; } // namespace detail diff --git a/test/base-test.cc b/test/base-test.cc index 40cc3810..92415cbd 100644 --- a/test/base-test.cc +++ b/test/base-test.cc @@ -874,6 +874,24 @@ struct custom_container { auto operator[](size_t) -> char& { return data; } }; +struct phantom_subscript_operator_container { + std::vector buffer; + + using value_type = char; + + auto size() const noexcept -> size_t { return buffer.size(); } + + auto data() noexcept -> char* { return buffer.data(); } + + auto data() const noexcept -> const char* { return buffer.data(); } + + void resize(size_t n) { buffer.resize(n); } + + void push_back(const char& value) { buffer.push_back(value); } + + operator const char*() const noexcept { return data(); } +}; + FMT_BEGIN_NAMESPACE template <> struct is_contiguous : std::true_type {}; FMT_END_NAMESPACE @@ -884,6 +902,7 @@ TEST(base_test, is_contiguous) { EXPECT_TRUE((fmt::is_contiguous::value)); EXPECT_TRUE((fmt::is_contiguous>::value)); EXPECT_FALSE((fmt::is_contiguous>::value)); + EXPECT_FALSE((fmt::is_contiguous::value)); } TEST(base_test, format_to_custom_container) {