@15:11 funny. that is in the STL now in c++23 as std::ranges::views::adjacent with an alias of std::ranges::views::pairwise for adjacent. It doesn't call a functor but rather returns a range of tuples, which you can then put into std::foreach for example. there is also std::ranges::views::slide which returns a range of ranges rather than a range of tuples. here is my take on all_pairs @ 21:55 template auto all_pairs(R&& range) { const auto SIZE = static_cast(std::ranges::distance(range)); // generate all unique index pairs auto idxPairs = std::views::cartesian_product(std::views::iota(0, SIZE), std::views::iota(0, SIZE)) | std::views::filter( [](const auto& idxPair) { const auto& [i, j] = idxPair; return i != j; } ); return std::views::transform( idxPairs, [&range](const auto& idxPair) { const auto& [i, j] = idxPair; return std::make_tuple(range[static_cast(i)], range[static_cast(j)]); } ); } if you wanted to only use ascending indexes in the pairs, adjust the filter predicate to return i < j;
I wish he explained 12:00 why you would NOT want to use post-increment first++ operators instead of ++first , he even says the compile down to the same thing. What is the big deal about post-increment operators in the STD/STL
He mentions the reason some time later. Using the post-increment creates another requirement imposed on the iterator. If you have less requirements then the algorithm can be applied in a wider variety of cases. Another case mentioned later uses the same reasoning when using first != last instead of first < last. All iterator types support !=, but not all of them support
They are inefficient. The canonical way to implement them is to save the old iterator value, call ++iterator, return the old value. I would only call the post-increment iterator if I needed the old value and do wish to increment.
adjacent_pair is quite an useful algorithm; please propose or add to Boost. Also I support the suggestion to use good names, but it seems that the STL is a major offender here (e.g. std::remove_copy which has nothing to with std::remove but more like copy_if_not or copy_omit).
I find std::algorithms very hard/non-intuitive to use. I have to always go online to refresh my memory on what each algorithm does and the order of its arguments and outputs. I would prefer a more functional programming or range syntax.
They become much easier to use after reading Alexander Stepanov' Elements of Programming and watching is A9 lectures here on youtube. It was a bit disappointing from the presenter btw not to mention his name in the first place.
yoooooooo thank you for sharing that im loving his lectures. real in depth analysis with basic examples, and historical facts about programming . so awesome.
I'm pretty sure that std::copy example has a bug in it (if 'first' points to an element after 'last' it will break). That for loop should be using "first < last" as the end condition to work around that. (hopefully that's how a real implementation does it).
Input Iterators are not expected to have operator < defined. As was mentioned, the minimum amount of constraints are placed on types in the STL algorithms. Also, the documentation for std::copy says it will copy the range [first, last). If your parameters cannot represent that range, then you are invoking undefined behaviour. As an example, lets say we have an 8-bit micro with address range 0x00 to 0xFF. I want to copy the very last and first byte of the valid memory range to somewhere else. // Please excuse the use of C casts uint8_t* first = (uint8_t*)0xFF; uint8_t* last = (uint8_t*)0x01; uint8_t* out = (uint8_t*)0xAA; std::copy(first, last, out); This is both valid and well defined on my system, as pointers are 8-bit and will wrap from 0xFF to 0x00, thereby representing a valid copyable range.
I feel you. It's a "function template". It's a template that serves to specify functions. Not a template function, and not a templated function. Just like `std::vector` is not a class, it's a class template. `std::vector` is a class. I like the talk very much and recommend it to my students in my course, but many speakers, including some living legends, are rather imprecise about that and it does bother me a tad.
C++ has nice features but going to be so complex and unreadable. for system programming the system should be visible and understandable with simple concepts, C is much better in this way. with all respect to all efforts behind C++, unfortunately, it try abstract itself and the whole system in the wrong way. complexity over complexity.
I just found all these CppCon videos. Not a C++ dev by any means, but these lectures are so good. Thanks!
Nice talk, but a bit too 'entry level'. May be follow-up next year?
I agree. It's a good introduction, but not very satisfying for anyone who's already written quite a few STL-style algorithms.
@15:11 funny. that is in the STL now in c++23 as std::ranges::views::adjacent with an alias of std::ranges::views::pairwise for adjacent. It doesn't call a functor but rather returns a range of tuples, which you can then put into std::foreach for example. there is also std::ranges::views::slide which returns a range of ranges rather than a range of tuples.
here is my take on all_pairs @ 21:55
template
auto all_pairs(R&& range)
{
const auto SIZE = static_cast(std::ranges::distance(range));
// generate all unique index pairs
auto idxPairs = std::views::cartesian_product(std::views::iota(0, SIZE), std::views::iota(0, SIZE))
| std::views::filter(
[](const auto& idxPair)
{
const auto& [i, j] = idxPair;
return i != j;
}
);
return std::views::transform(
idxPairs,
[&range](const auto& idxPair)
{
const auto& [i, j] = idxPair;
return std::make_tuple(range[static_cast(i)], range[static_cast(j)]);
}
);
}
if you wanted to only use ascending indexes in the pairs, adjust the filter predicate to return i < j;
I see video two times
1. Just to understand English
2. To Understand Algorithm.
Practical Gentle Introduction.
a f( first, first[-1] ) could be more efficient. But I guess the compiler does this optimization by itself, but its not guaranteed.
but compile error is really not so friendly
I wish he explained 12:00 why you would NOT want to use post-increment first++ operators instead of ++first , he even says the compile down to the same thing. What is the big deal about post-increment operators in the STD/STL
He mentions the reason some time later. Using the post-increment creates another requirement imposed on the iterator. If you have less requirements then the algorithm can be applied in a wider variety of cases. Another case mentioned later uses the same reasoning when using first != last instead of first < last. All iterator types support !=, but not all of them support
They are inefficient. The canonical way to implement them is to save the old iterator value, call ++iterator, return the old value.
I would only call the post-increment iterator if I needed the old value and do wish to increment.
adjacent_pair is quite an useful algorithm; please propose or add to Boost. Also I support the suggestion to use good names, but it seems that the STL is a major offender here (e.g. std::remove_copy which has nothing to with std::remove but more like copy_if_not or copy_omit).
std::remove_copy performs the same function as std::remove except it is not in place.
36:00
I find std::algorithms very hard/non-intuitive to use. I have to always go online to refresh my memory on what each algorithm does and the order of its arguments and outputs. I would prefer a more functional programming or range syntax.
They become much easier to use after reading Alexander Stepanov' Elements of Programming and watching is A9 lectures here on youtube. It was a bit disappointing from the presenter btw not to mention his name in the first place.
LOLLLLLL with how complex c++ is and you get those beautiful easy to use abstractions and you still complain... bruh...
He did mention him, at 29:13 and 30:01
yoooooooo thank you for sharing that im loving his lectures. real in depth analysis with basic examples, and historical facts about programming . so awesome.
u ar dumb
I'm pretty sure that std::copy example has a bug in it (if 'first' points to an element after 'last' it will break). That for loop should be using "first < last" as the end condition to work around that. (hopefully that's how a real implementation does it).
Input Iterators are not expected to have operator < defined. As was mentioned, the minimum amount of constraints are placed on types in the STL algorithms. Also, the documentation for std::copy says it will copy the range [first, last). If your parameters cannot represent that range, then you are invoking undefined behaviour. As an example, lets say we have an 8-bit micro with address range 0x00 to 0xFF. I want to copy the very last and first byte of the valid memory range to somewhere else.
// Please excuse the use of C casts
uint8_t* first = (uint8_t*)0xFF;
uint8_t* last = (uint8_t*)0x01;
uint8_t* out = (uint8_t*)0xAA;
std::copy(first, last, out);
This is both valid and well defined on my system, as pointers are 8-bit and will wrap from 0xFF to 0x00, thereby representing a valid copyable range.
Ionuț Leonte Also watch around 38:00
I find this clow funn.
UwU
"A templated function" ... I hate that expression.
Daniel Jesús Valencia Sánchez Well then maybe this talk is not for you
I feel you. It's a "function template". It's a template that serves to specify functions. Not a template function, and not a templated function. Just like `std::vector` is not a class, it's a class template. `std::vector` is a class.
I like the talk very much and recommend it to my students in my course, but many speakers, including some living legends, are rather imprecise about that and it does bother me a tad.
There is no such thing as a 'templated function'. It's a 'function template' :)
C++ has nice features but going to be so complex and unreadable. for system programming the system should be visible and understandable with simple concepts, C is much better in this way. with all respect to all efforts behind C++, unfortunately, it try abstract itself and the whole system in the wrong way. complexity over complexity.
C is a part of CPP so everything you describe is opt-in.
adjacent_pair is very useful 👌
Would be better if he shown how to use it in the code with an example