I have a piece of code that uses the ranges library of C++20, taken from this SO anwer. The code is rejected by some compiler (versions) and some older GCC versions return garbage. Which compiler is right?
The code is supposed to print the elements of the first column in a std::vector<std::vector>
.
#include <vector>
#include <string>
#include <ranges>
#include <iostream>
int main()
{
// returns a range containing only the i-th element of an iterable container
auto ith_element = [](size_t i) {
// drop the first i elements in the range and take the first element from the remaining range
return std::views::drop(i) | std::views::take(1);
};
// returns a range over the i-th column
auto column = [ith_element](size_t i) {
return std::views::transform(ith_element(i)) | std::views::join; // returns a range containing only the i-th elements of the elements in the input range
};
std::vector<std::vector<std::string>> myvec = {
{ "a", "aaa", "aa"},
{"bb", "b", "bbbb"},
{"cc", "cc", "ccc"}
};
for (auto const& v: myvec | column(0)){
std::cout << v << std::endl;
}
return 0;
}
Output:
With GCC 10.1, 10.2, 10.3, 10.4:
b
Doesn't compile with GCC 11.1 and clang.
error: no match for 'operator|' (operand types are 'std::vector<std::vector<std::__cxx11::basic_string<char> > >' and 'std::ranges::views::__adaptor::_Pipe<std::ranges::views::__adaptor::_Partial<std::ranges::views::_Transform, std::ranges::views::__adaptor::_Pipe<std::ranges::views::__adaptor::_Partial<std::ranges::views::_Drop, long unsigned int>, std::ranges::views::__adaptor::_Partial<std::ranges::views::_Take, int> > >, std::ranges::views::_Join>')
Expected
a
bb
cc
Works as expected with GCC 11.2, 11.3, 12.1, 12.2, MSVC 19.33