My understanding is that there's no {fmt} equivalent to copy(v, ostream_iterator<int>(cout)) at present. If there isn't any equivalent, is there interest in adding such support?
This would be a boon to generic programming and would help ease the transition from streams to {fmt}.
Example use-cases:
// simple replacement for the above
copy(v, fmt::format_iterator<int>());
// added constructor overloads for prefixing and suffixing static output
copy(v, fmt::format_iterator<int>(fmt::prefix("\n")));
copy(v, fmt::format_iterator<int>(fmt::suffix("\n")));
copy(v, fmt::format_iterator<int>(fmt::prefix("value"), fmt::suffix("\n")));
// with a custom format function
auto log_error = [&some_file, &prefix, &suffix](auto const& data) {
fmt::print(stderr, "Some log text {} {} {}", prefix, data, suffix);
};
copy(v, fmt::format_iterator<int>(my_print));
I may be a bit dense, but I don't really get what you are trying to accomplish (and what the lambda is for). It might help to give some kind of pseudo implementation of your proposed iterator in terms of the existing API.
I don't really get what you are trying to accomplish
I'd like to see an equivalent to ostream_iterator be offered.
copy(v, fmt::format_iterator<int>());
This particular algorithm will copy the contents of the range v to stdout, as if by
for (auto const& i : v) {
fmt::print("{}", i);
}
(and what the lambda is for)
The lambda allows for some custom functionality, for example, being able to print to stderr.
It might help to give some kind of pseudo implementation of your proposed iterator in terms of the existing API.
See my Compiler Explorer hack for a rough example.
is there interest in adding such support?
Sure.
copy(v, fmt::format_iterator<int>(fmt::prefix("\n"))); copy(v, fmt::format_iterator<int>(fmt::suffix("\n"))); copy(v, fmt::format_iterator<int>(fmt::prefix("value"), fmt::suffix("\n")));
Why not tap into the {fmt}'s formatting potential and pass the format string instead of providing prefix and suffix, e.g.
copy(v, fmt::format_iterator<int>("{}\n"));
copy(v, fmt::format_iterator<int>("{}\n"));
copy(v, fmt::format_iterator<int>("value{}\n"));
?
Then you could also do things like
// format values in hexadecimal:
copy(v, fmt::format_iterator<int>("{:x}\n"));
// format each value on a separate line, right-aligned:
copy(v, fmt::format_iterator<int>("{:>10}\n"));
A potential alternative to format_iterator would be extending the ranges API to support prefixes and suffixes:
fmt::print("{}", fmt::range(v, fmt::suffix("\n")));
Why not tap into the {fmt}'s formatting potential and pass the format string instead of providing prefix and suffix, e.g.
copy(v, fmt::format_iterator<int>("{}\n")); copy(v, fmt::format_iterator<int>("{}\n")); copy(v, fmt::format_iterator<int>("value{}\n"));?
Then you could also do things like
// format values in hexadecimal: copy(v, fmt::format_iterator<int>("{:x}\n")); // format each value on a separate line, right-aligned: copy(v, fmt::format_iterator<int>("{:>10}\n"));
Brilliant. I'm sold!
An potential alternative to format_iterator would be extending the ranges API to support prefixes and suffixes
I'm concerned that it won't be compatible with generic code. There may be some function where I want to perform a write, but not necessarily perform a print.
It might be nice to have both.
After a bit of design, I think there should be at least two iterators:
print_iterator, which is analogous to fmt::print.format_iterator, which is analogous to fmt::format.I think there should be at least two iterators
Seems reasonable.
It's not mergeable with upstream, but you can find a WIP Pull Request for print_iterator on my fork. I'd like to publish a proposal for this in Kona, so any feedback is much appreciated.
There are a few design considerations that require thinking about before I push my format_iterator, but please stay tuned!
Cool! I left some comments on that PR.
Why is
// with a custom format function
auto log_error = [&some_file, &prefix, &suffix](auto const& data) {
fmt::print(stderr, "Some log text {} {} {}", prefix, data, suffix);
};
copy(v, fmt::format_iterator<int>(my_print));
better than
for( auto const& x: v )
{
fmt::print(stderr, "Some log text {} {} {}", prefix, x, suffix);
}
?
Why is
// with a custom format function auto log_error = [&some_file, &prefix, &suffix](auto const& data) { fmt::print(stderr, "Some log text {} {} {}", prefix, data, suffix); }; copy(v, fmt::format_iterator<int>(my_print));better than
for( auto const& x: v ) { fmt::print(stderr, "Some log text {} {} {}", prefix, x, suffix); }?
Given what you've provided, it isn't necessarily better. The original use-case didn't foresee the design being _that_ different to ostream_iterator. @vitaut and I discussed why I'm in favour of adding iterator support above:
An potential alternative to format_iterator would be extending the ranges API to support prefixes and suffixes
I'm concerned that it won't be compatible with generic code. There may be some function where I want to perform a write, but not necessarily perform a print.
Take something such as unique_copy or a user-defined sort_copy, for example.
Well, I'm going by the examples you yourself provided. (Note that the alternative works for non-int too.)
For unique_copy or similar, I would expect the idiomatic way in C++20 to be range-for over an adapted range.
Closing the issue, but a PR to introduce some form of a format iterator is welcome.