This is such a cool video! Very useful and to the point! Exactly whay I needed!
@mjKlaim2 жыл бұрын
I remember catching such kind of bugs (from the beginning) in a bunch of unit tests simply by running the test with visual studio Debug mode which also adds iterator checks.
@sheeftz2 жыл бұрын
7:33 You used a lamda with a side effect . There is no explicit requirement for the function parameter in ranges::transform not to have side effects, but are you sure that it means it guarantees to call the transformation function object in the expected order and once per object? There is no explicit guarantees of that.
@yogthemuskrat2 жыл бұрын
There is no such guarantee. Even more - there is a well known "filter | transform" problem when transform gets called more times that you'd expect.
@sheeftz2 жыл бұрын
@@yogthemuskrat Well, then it's broken in the most dangerous way things can be broken in c++. He'd better fix this before people start thinking that lambdas with side effect in views is a smart thing to do.
@cristian-si1gb2 жыл бұрын
@@sheeftz Actually, this was always a problem with STL algorithms. See "std::find() is Broken!" by Sean Parent kzbin.info/www/bejne/aHekmmWjg76dfKM&ab_channel=CppCon
@danrobinson286611 ай бұрын
I tried the following and expected to see the index values start at 5, that was not the case. for(const auto &[index, elem] : get_data()| std::ranges::views::transform(make_index) | std::ranges::views::drop(5)) { fmt::print("{}: {} ", index, elem); }
@KennyMinigun2 жыл бұрын
That std::ranges::views is quite a mouthful. I just looked up on cppreference, and bless the creators there is an alias namespace std::views = std::ranges::views.
@TheMR-7772 жыл бұрын
I always define an alias of myself, before using ranges, namespace rg = std::ranges; namespace vs = rg::views; In this way, you can also easily switch b/w std::ranges and range-v3.
@Voy23782 жыл бұрын
@@TheMR-777 I use sv and sr but yeah full namespaces are a bad joke
@oschonrock2 жыл бұрын
For the record, after playing around on CE, it turns out that gcc 12.2 with libstdc++ can run the above code (trunk is not required) and clang trunk with libc++ can also run it. So some progress!
@victotronics2 жыл бұрын
Very nice tutorial. So with that last example you basically have the python "enumerate" iterator. How hard would "zip" be? Is that going to be in 23?
@cppweekly2 жыл бұрын
Zip is in 23, yes
@yogthemuskrat2 жыл бұрын
There is actually an `enumerate` adapter on Range-V3, btw.
@StephenWarren2 жыл бұрын
See also std::ranges::views::iota, std::ranges::iota_view. iterate_with_index() is basically zip with iota.
@DiegoHavenstein2 жыл бұрын
The transform + make index example is something I tried out recently, but used zip(iota(0), vec) instead. Zip has a special case when 2 args are passed so a std::pair is returned just as in the example from the video
@MohammadJK1972 ай бұрын
I liked and subscribed within 3min. awesome video. 😛
@sky_is_the_limit_135 ай бұрын
Great video! at @2:16 the primary issue is about the vectors having different memory addresses, even though they contain the same data, right?
@cppweekly4 ай бұрын
Correct, we've got the begin() from one vector and the end() from a completely different vector, so we're trying to iterate between two completely unrelated objects.
@oschonrock2 жыл бұрын
Doesn't number 3) have lifetime issues as well? Because the ranged for is transformed into a begin() call and then the loop and by then the temporary is gone? Or was that a different scenario, or is now fixed?? Or does the drop view actually save us here, because it extends the lifetime of the temporary vector until we have finished iterating it - because it's lazy. ?
@cristian-si1gb2 жыл бұрын
It's safe, the lifetime of the owning_view is extended by __range and begin/end are called on it. auto && __range = range-expression ; auto __begin = begin-expr ; auto __end = end-expr ; for ( ; __begin != __end; ++__begin) { range-declaration = *__begin; loop-statement }
@oschonrock2 жыл бұрын
@@cristian-si1gb Thanks. I guess I had that "electric tingling alert" as soon as I saw the "2 step temporary", which is normally what produces this problem. But I guess these views are designed to capture the thing in front of the pipe in some kind of internal reference (that's the "owning" part?), and then, as you say, the view becomes a "one step temporary" which is safely lifetime extended by auto&& __range reference. Is that right?
@cristian-si1gb2 жыл бұрын
@@oschonrock All views will by default apply std::views::all on the range they're based on. It's a bit too much to explain in depth here, Tristan Brindle just had a talk explaining why and how this works: kzbin.info/www/bejne/gmHFmY2ma62Aeq8&ab_channel=CppNorth
@VictorHugoVideos2 жыл бұрын
The make_index trick was something that I've always wondered why it didn't existed already.
@ChristianBrugger Жыл бұрын
I find ranges very exciting. Two problems I struggled with adopting it in my application: * compile times exploding, up to 10 seconds for a single cpp file in both clang and MSVC * very inefficient code generation for some Code I would love to get more deeper insights into this and waiting for someone to cover it. I know sone of it is a quality of implementation problem, but I don't think fully. Some is me using the library in a non optimal way.
@cppweekly Жыл бұрын
Ranges are complex, so I'm honestly not surprised. But I have not measured it myself. I think in many cases the expressiveness will outweigh the costs.
@alexbalrus Жыл бұрын
На первый взгляд сложные конструкции. Почти ничего не понял) Кто-нибудь уже оценил - ranges это действительно замена stl? Есть в них значительная польза?
@literallynull3 ай бұрын
Используй только то, что упрощает код и делает его читабельнее. Удобно использовать *for (auto& it : std::views::reverse(container))* вместо *for(auto it = container.rbegin(); it != container.rend(); ++it)*
@hammad78298 ай бұрын
how do you type so fast??
@cppweekly7 ай бұрын
With fast forward
@c0d3_m0nk3y2 жыл бұрын
This is basically the same as LINQ in C#, isn't it?
@OperationDarkside2 жыл бұрын
Correct me if I'm wrong, but LINQ was supposed to look like SQL but inside C# code. I don't know the C# equivalent, but Java has the streams API, that is kind of similar.
@c0d3_m0nk3y2 жыл бұрын
C# LINQ: data .Where(a => a % 2 == 0) .Select(a => a * a) .Take(2); C++20 ranges: data | filter([](const int& a) { return a % 2 == 0; ) | transform([](const int& a) { return a * a; }) | take(2);
@keshkek2 жыл бұрын
@@c0d3_m0nk3y if you want to use sql like code in c++ you should write DSL which will detect errors etc oni compile time instead of using common code
@DrPastah2 жыл бұрын
std::range isn't a thing for C++14 is it?
@ChrisCarlos642 жыл бұрын
It came with C++20, so no it isn't for C++14
@yogthemuskrat2 жыл бұрын
There is range-v3 for that (older versions).
@PaulMetalhero2 жыл бұрын
The scripting engine, please!
@cppweekly2 жыл бұрын
If only I could drop my contract work and have all of my time to spend on these things!
@billynugget71022 жыл бұрын
Im not sure about everyone else but a simple for loop with an index (yes this feature does still exist) is much more understandable than what has been presented here. Despite it being more expressive (if you know what is going on) it continues the problem of polluting c++ with more special keywords and libraries that make it less and less accessible than the average enthusiast. “Idiots idolise complexity, a genius strives for simplicity”
@yogthemuskrat2 жыл бұрын
A raw loop is easier to understand when it is simple. But with every new condition (like, skip first element, reverse etc.) it gets messier and messier. And it gets not just harder to read but also much more error prone. View adapter on other hand make it easier to follow the "respect the layers of abstraction" principle - that is they strip away all the details of HOW you implement from WHAT you want to do.
@billynugget71022 жыл бұрын
@@yogthemuskrat bro if you can’t understand for(int i = 1; i
@yogthemuskrat2 жыл бұрын
@@billynugget7102 You should add a check, to ensure that container is not empty. A little thing, but it adds verbosity and breaks outside the loop itself.
@hstrauss22142 жыл бұрын
A simple for loop with an index might be more understandable, but it is also more restrictive. Just change the vector in the example to a list, an it won't work any more. The presented solution is more general and therefore very much has its justification.
@billynugget71022 жыл бұрын
@@hstrauss2214 yeah you can justify it that wat but im saying becuase its so clunky many devs will opt for a more simple (and arguably less “expressive”) solution
@anon_y_mousse2 жыл бұрын
I know it'll never happen, but C++ needs a slice operator. What you just showed with std::ranges::views makes me want to barf.
@valizeth40732 жыл бұрын
I mean, its not far from many other languages piping operator, like elixirs |>
@spjuanjoc2 жыл бұрын
Just FYI, with fmt/ranges it should be possible to: //... #include //... fmt::print("{}", get_data() | std::ranges::views::drop(1)); //...
@toRatnesh2 жыл бұрын
This is why sanitizer builds are helpful Compiling with sanitizer (-fsanitize=address) gives error for this auto result = std::all_of(get_data().begin(), get_data().end(), [](const int i){ return i < 5;});
@cppweekly2 жыл бұрын
Hmm... I definitely tested with asan and didn't get this error caught, must have used the wrong combination of compiler/tests
@toRatnesh2 жыл бұрын
I was using count_if and for_each instead of all_of and got sanitizer error, so I assumed behavior will be same for all_of but it has different behavior