Sorry, I was searching a lot, but I still do not understand.
Let's assume that I want to read line by line with an istream_view
using a line proxy and convert the result to lowercase.
It would be nice, if I could write
#include <iostream>
#include <sstream>
#include <string>
#include <iterator>
#include <ranges>
#include <algorithm>
namespace rng = std::ranges;
struct CompleteLine { // Line Proxy for the input Iterator
friend std::istream& operator>>(std::istream& is, CompleteLine& cl) { std::getline(is, cl.completeLine); return is; }
operator std::string() const { return completeLine; } // cast operator
std::string completeLine{};
};
std::istringstream iss{ R"(1 Line AAA
2 Line BBB
3 Line CCC)" };
int main() {
for (const std::string& line : rng::istream_view<CompleteLine>(iss) | std::views::transform(std::tolower)) {
std::cout << line << '\n';
}
}
But obviously I cannot. I does not compile.
How would I use ranges, views and pipes to get a correct solution?
CodePudding user response:
How would I use ranges, views and pipes to get a correct solution?
Your attempt is correct. However, it should be noted that rng::istream_view<CompleteLine>(iss)
will generate a range whose elements are string
s, while tolower
acts on a single character.
This should work
for (const std::string& line : std::views::istream<CompleteLine>(iss)
| std::views::transform([](std::string line) {
std::ranges::transform(line, line.begin(),
[](auto c) { return std::tolower(c); });
return line;
})) {
std::cout << line << '\n';
}
Prefer views::istream
over ranges::istream_view
.
Prefer using lambdas instead of taking the address of toupper
directly, the standard does not allow to do this.