After a career diversion, I am trying to get up to speed with std::views (and functional programming in general). I am using the '|' (pipe) operator with std::views::filter on a vector, and I am puzzled why some code structures compile and others don't.
This code creates a vector of vectors of int
, then filters them by sum. I've commented the three statements that are confusing me, the first two of which compile and the third doesn't.
Compilation error is:
'|': no operator found which takes a left-hand operand of type 'std::vector<std::vector<int,std::allocator<int>>,std::allocator<std::vector<int,std::allocator<int>>>>' (or there is no acceptable conversion)
(Using MSVC19, compiled with /std:c++latest
)
I am puzzled as to why this doesn't compile while (2) especially does?
#include <vector>
#include <numeric>
#include <ranges>
template<typename T>
auto buildMultiples(const std::vector<T>& base)
{
std::vector<std::vector<T>> vRet;
for(T n= 1; n <= 5; n++)
{
auto v = base;
for (auto& m : v) m *= n;
vRet.push_back(v);
}
return vRet;
}
template<typename T>
struct sumGreaterThan
{
T _limit{ 0 };
auto operator()(const std::vector<T>& v) {return std::accumulate(v.cbegin(), v.cend(), 0) > _limit;}
};
int main()
{
using namespace std;
vector<int> nums{1,2,3,4,5,6,7,8,9};
auto mults = buildMultiples(nums);
for (auto& m : buildMultiples(nums)) {} //1. Compiles
sumGreaterThan sumFilter{ 10 };
auto vecs = buildMultiples(nums);
for (auto& m : vecs | views::filter(sumFilter)) {} //2. Compiles
for (auto& m : buildMultiples(nums) | views::filter(sumFilter)) {} //3. Compilation Error!!
for (auto vecs = buildMultiples(nums); auto & m : vecs | views::filter(sumFilter)) {} // 4. Compiles. Thanks @Aryter
}
As the pipe is like a redirection operator, we can use it in different commands. Some of the options are mentioned below : 1) grep -I filename | sort: In this, the grep result will be fetched from the filename and will act as an input to the sort command, and the sort command will sort the data in default mode.
The pipe command syntax is straightforward. As the pipe is like a redirection operator, we can use it in different commands. Some of the options are mentioned below :
In .NET, you implement named pipes by using the NamedPipeServerStream and NamedPipeClientStream classes. See How to: Use Named Pipes for Network Interprocess Communication.
Pipe Operations in .NET. Pipes provide a means for interprocess communication. There are two types of pipes: Anonymous pipes. Anonymous pipes provide interprocess communication on a local computer. Anonymous pipes require less overhead than named pipes but offer limited services. Anonymous pipes are one-way and cannot be used over a network.
This is passing an lvalue vector
into filter
:
vecs | views::filter(sumFilter)
whereas this is passing an rvalue vector
into filter
:
buildMultiples(nums) | views::filter(sumFilter)
The current rule, which compilers implement, is that range adaptor pipelines cannot take rvalue non-view ranges (like vector
, string
, etc.). This is because the pipeline itself is non-owning (views were non-owning), and exists as a safety mechanism to prevent dangling.
The new rule, recently adopted as a defect, would allow this could and would cause filter
to own the result of buildMultiples
(this is P2415), but compilers don't implement it quite yet. With this change, your other version would also have compiled.
So for now, you will have to keep writing it this way (as you are already doing):
auto vecs = buildMultiples(nums);
for (auto& m : vecs | views::filter(sumFilter)) { ... }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With