diff --git a/include/fmt/format.h b/include/fmt/format.h index 65d27161..3d0abd41 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -3420,15 +3420,15 @@ arg_join join(It begin, Sentinel end, wstring_view sep) { \endrst */ template -arg_join, detail::sentinel_t, char> -join(const Range& range, string_view sep) { +arg_join, detail::sentinel_t, char> +join(Range&& range, string_view sep) { return join(std::begin(range), std::end(range), sep); } template -arg_join, detail::sentinel_t, +arg_join, detail::sentinel_t, wchar_t> -join(const Range& range, wstring_view sep) { +join(Range&& range, wstring_view sep) { return join(std::begin(range), std::end(range), sep); } diff --git a/test/ranges-test.cc b/test/ranges-test.cc index 46208e8d..7f1c845b 100644 --- a/test/ranges-test.cc +++ b/test/ranges-test.cc @@ -153,3 +153,39 @@ TEST(RangesTest, JoinSentinel) { EXPECT_EQ("{'h', 'e', 'l', 'l', 'o'}", fmt::format("{}", hello)); EXPECT_EQ("h_e_l_l_o", fmt::format("{}", fmt::join(hello, "_"))); } + +// A range that provides non-const only begin()/end() to test fmt::join handles that +// +// Some ranges (eg those produced by range-v3's views::filter()) can cache information +// during iteration so they only provide non-const begin()/end(). +template +class non_const_only_range { + private: + std::vector vec; + + public: + using const_iterator = typename ::std::vector::const_iterator; + + template + explicit non_const_only_range(Args &&...args) : vec( ::std::forward( args )... ) {} + + const_iterator begin() { + return vec.begin(); + } + const_iterator end() { + return vec.end(); + } +}; + +TEST(RangesTest, JoinRange) { + non_const_only_range x( 3, 0 ); + EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(x, ","))); + EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(non_const_only_range( 3, 0 ), ","))); + + std::vector y( 3, 0 ); + EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(y, ","))); + EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(std::vector( 3, 0 ), ","))); + + const std::vector z( 3, 0 ); + EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(z, ","))); +}