Make join() handle non-const-only begin/end ranges

See fmtlib/fmt#1784.

Add tests that demonstrate the problem and check obvious variations.
This commit is contained in:
Tony Lewis 2020-07-20 16:58:21 +01:00
parent d69e2da221
commit a018b09aab
2 changed files with 40 additions and 4 deletions

View File

@ -3420,15 +3420,15 @@ arg_join<It, Sentinel, wchar_t> join(It begin, Sentinel end, wstring_view sep) {
\endrst \endrst
*/ */
template <typename Range> template <typename Range>
arg_join<detail::iterator_t<const Range>, detail::sentinel_t<const Range>, char> arg_join<detail::iterator_t<Range>, detail::sentinel_t<Range>, char>
join(const Range& range, string_view sep) { join(Range&& range, string_view sep) {
return join(std::begin(range), std::end(range), sep); return join(std::begin(range), std::end(range), sep);
} }
template <typename Range> template <typename Range>
arg_join<detail::iterator_t<const Range>, detail::sentinel_t<const Range>, arg_join<detail::iterator_t<Range>, detail::sentinel_t<Range>,
wchar_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); return join(std::begin(range), std::end(range), sep);
} }

View File

@ -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("{}", hello));
EXPECT_EQ("h_e_l_l_o", fmt::format("{}", fmt::join(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 <typename T>
class non_const_only_range {
private:
std::vector<T> vec;
public:
using const_iterator = typename ::std::vector<T>::const_iterator;
template <typename... Args>
explicit non_const_only_range(Args &&...args) : vec( ::std::forward<Args>( args )... ) {}
const_iterator begin() {
return vec.begin();
}
const_iterator end() {
return vec.end();
}
};
TEST(RangesTest, JoinRange) {
non_const_only_range<int> 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<int>( 3, 0 ), ",")));
std::vector<int> y( 3, 0 );
EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(y, ",")));
EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(std::vector<int>( 3, 0 ), ",")));
const std::vector<int> z( 3, 0 );
EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(z, ",")));
}