Comments (5)
Here's a test that makes much more sense to me!
TEST_CASE("filter predicate and pipeline get the input value")
{
const std::vector<std::vector<int>> original = {{1,2,3,4}, {5,6,7,8}};
std::vector<std::vector<int>> input = original;
std::vector<std::vector<int>> valueSeenByThePredicate;
auto const copyPassthroughFilter = pipes::filter(
[&valueSeenByThePredicate]
(std::vector<int> value)
{
valueSeenByThePredicate.push_back(value);
return true;
});
std::vector<std::vector<int>> results;
std::copy(std::make_move_iterator(begin(input)), std::make_move_iterator(end(input)), copyPassthroughFilter >>= pipes::push_back(results));
REQUIRE(std::equal(original.cbegin(), original.cend(), valueSeenByThePredicate.cbegin()));
REQUIRE(std::equal(original.cbegin(), original.cend(), results.cbegin()));
}
from pipes.
Oh, and then the precise issue is not double move, but simply use after move if the predicate moves the value. Whatever the rest of the pipeline does it will do it on moved from values!
And I did sound like you had a choice for the fix, but basically you can only forward at the last use of a variable.
The only flexibility you have is to reorder operations, if you feel it is more beneficial to forward during one operation than the other. Most of the time you don't even have the freedom to reorder, though.
from pipes.
Ok, I'll stop the monologue after this, I promise.
To me there is one issue, and 2 ways to solve it.
The issue is: in the current implementation, if the predicate takes its argument by value, the value actually gets moved! This means that a harmless looking predicate taking its argument by value will destroy what is passed to the pipeline tail. That is a surprising effect that must be avoided.
The test to detect this is even more simple than the ones suggested above.
Now the 2 solutions I can suggest are to change line 19 of filter.hpp from
if (predicate_(FWD(value)));
to:
if (predicate_(value));
orif (predicate_(static_cast<const Value&>(value)));
Both solutions solve the above mentioned issue. They also both fail to compile if the predicate takes the value by rvalue reference (Value&&), which seems correct to me. The only difference is: with solution 2, the predicate cannot take the value by lvalue reference (Value&) either. Solution 1 allows it, and thus the predicate would be allowed to modify the value it is passed. It think it is much less error-prone to go with solution 2. And Pipes being what they are, if you want to modify the value before passing it to the next pipe, you should use a separate pipe to do it, rather than the predicate of a filter pipe.
That's it. I'll be happy to look at the other pipes if you can tolerate 2 full pages of comments for each of my findings :)
from pipes.
Another thing that could be done is use detection idiom to ensure that the predicates are callable with a const lvalue ref. This had the added advantages of allowing better error messages, and of being similar to what might be done with concepts in the (near?) future.
from pipes.
Thanks! I went for solution 1 because it seems to me more consistent with the STL.
The fix is in this commit: b79dcfb
from pipes.
Related Issues (20)
- Concurrency question HOT 3
- Make pipes available on godbolt.org HOT 2
- W4 flag prevents compilation with MSVC HOT 2
- Compile error with toupper and MSVC compiler
- [New pipes] pipes::values and pipes::keys for std::map ; pipes::erase
- Execution policy HOT 4
- add count end pipe HOT 3
- Start marking releases HOT 2
- fifo HOT 2
- nullopt
- Allow pipelines to have a result (sink?) object HOT 3
- [discussion] Implementing `drop_last` for pipes HOT 2
- CPPCON video HOT 1
- Missing #include <optional> HOT 1
- error: no viable overloaded '>>=' HOT 1
- Create a single pipe for multiple data
- could using macro FWD be removed?
- Question: What would be a good demonstration of pipeline stages where each stage is multi-threaded? HOT 1
- Pipes
- Seems like the simplest case isn't working here!
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from pipes.