What is the correct practice capturing return value of boost::make_iterator_range in following scenarios:
When used in range based for loop:
for (auto&& val : boost::make_iterator_range(...))// <-- is `auto&&` the right way?
When used as formal parameter:
DoStuff(boost::make_iterator_range(...));
template<class Iterator>
void DoStuff(Iterator&& it){}// <-- is Iterator&& the right way?
for (auto&& val : boost::make_iterator_range(...))// <-- is `auto&&` the right way?
The return value of make_iterator_range is not stored in val. val simply stores the return value of the dereferencing of the iterators: the element, not the entire range.
auto&& creates a forwarding reference to the element.
DoStuff(boost::make_iterator_range(...));
template<class Iterator>
void DoStuff(Iterator&& it){}// <-- is Iterator&& the right way?
Using the name Iterator belies a misunderstanding: make_itetator_range is not an iterator, it is a range defined by iterators.
template<class Range>
void DoStuff(Range&& r){}
This does not change the behaviour of the code, but it was like having a variable of type int named Double: pointlessly or aggressively confusing.
In any case, Range&& r in this context is also a forwarding reference.
A forwarding reference in a type deduction context can bind to either an lvalue or rvalue. It can cause reference lifetime extension as well.
In both of these situations, auto&& and Range&& are reasonable approaches, but so would auto const&, auto& or auto in the first case, and in the second Range const& or Range have their advantages. They just mean different things.
So your solutions are one way that can be right, but there is no "one right way" for what to put there. I use forwarding references by default, but that is a matter of taste: others might choose to default to const& or values. And in some contexts, auto& would be proper (where your loop modifies the value and intends that modification to persist).
Related
const auto& would suffice if I want to perform read-only operations. However, I have bumped into
for (auto&& e : v) // v is non-const
a couple of times recently. This makes me wonder:
Is it possible that in some obscure corner cases there is some performance benefit in using forwarding references, compared to auto& or const auto&?
(shared_ptr is a suspect for obscure corner cases)
Update
Two examples that I found in my favorites:
Any disadvantage of using const reference when iterating over basic types?
Can I easily iterate over the values of a map using a range-based for loop?
Please concentrate on the question: why would I want to use auto&& in range-based for loops?
The only advantage I can see is when the sequence iterator returns a proxy reference and you need to operate on that reference in a non-const way. For example consider:
#include <vector>
int main()
{
std::vector<bool> v(10);
for (auto& e : v)
e = true;
}
This doesn't compile because rvalue vector<bool>::reference returned from the iterator won't bind to a non-const lvalue reference. But this will work:
#include <vector>
int main()
{
std::vector<bool> v(10);
for (auto&& e : v)
e = true;
}
All that being said, I wouldn't code this way unless you knew you needed to satisfy such a use case. I.e. I wouldn't do this gratuitously because it does cause people to wonder what you're up to. And if I did do it, it wouldn't hurt to include a comment as to why:
#include <vector>
int main()
{
std::vector<bool> v(10);
// using auto&& so that I can handle the rvalue reference
// returned for the vector<bool> case
for (auto&& e : v)
e = true;
}
Edit
This last case of mine should really be a template to make sense. If you know the loop is always handling a proxy reference, then auto would work as well as auto&&. But when the loop was sometimes handling non-proxy references and sometimes proxy-references, then I think auto&& would become the solution of choice.
Using auto&& or universal references with a range-based for-loop has the advantage that you captures what you get. For most kinds of iterators you'll probably get either a T& or a T const& for some type T. The interesting case is where dereferencing an iterator yields a temporary: C++ 2011 got relaxed requirements and iterators aren't necessarily required to yield an lvalue. The use of universal references matches the argument forwarding in std::for_each():
template <typename InIt, typename F>
F std::for_each(InIt it, InIt end, F f) {
for (; it != end; ++it) {
f(*it); // <---------------------- here
}
return f;
}
The function object f can treat T&, T const&, and T differently. Why should the body of a range-based for-loop be different? Of course, to actually take advantage of having deduced the type using universal references you'd need to pass them on correspondingly:
for (auto&& x: range) {
f(std::forward<decltype(x)>(x));
}
Of course, using std::forward() means that you accept any returned values to be moved from. Whether objects like this makes much sense in non-template code I don't know (yet?). I can imagine that using universal references can offer more information to the compiler to do the Right Thing. In templated code it stays out of making any decision on what should happen with the objects.
I virtually always use auto&&. Why get bitten by an edge case when you don't have to? It's shorter to type too, and I simply find it more... transparent. When you use auto&& x, then you know that x is exactly *it, every time.
const auto& would suffice if I want to perform read-only operations. However, I have bumped into
for (auto&& e : v) // v is non-const
a couple of times recently. This makes me wonder:
Is it possible that in some obscure corner cases there is some performance benefit in using forwarding references, compared to auto& or const auto&?
(shared_ptr is a suspect for obscure corner cases)
Update
Two examples that I found in my favorites:
Any disadvantage of using const reference when iterating over basic types?
Can I easily iterate over the values of a map using a range-based for loop?
Please concentrate on the question: why would I want to use auto&& in range-based for loops?
The only advantage I can see is when the sequence iterator returns a proxy reference and you need to operate on that reference in a non-const way. For example consider:
#include <vector>
int main()
{
std::vector<bool> v(10);
for (auto& e : v)
e = true;
}
This doesn't compile because rvalue vector<bool>::reference returned from the iterator won't bind to a non-const lvalue reference. But this will work:
#include <vector>
int main()
{
std::vector<bool> v(10);
for (auto&& e : v)
e = true;
}
All that being said, I wouldn't code this way unless you knew you needed to satisfy such a use case. I.e. I wouldn't do this gratuitously because it does cause people to wonder what you're up to. And if I did do it, it wouldn't hurt to include a comment as to why:
#include <vector>
int main()
{
std::vector<bool> v(10);
// using auto&& so that I can handle the rvalue reference
// returned for the vector<bool> case
for (auto&& e : v)
e = true;
}
Edit
This last case of mine should really be a template to make sense. If you know the loop is always handling a proxy reference, then auto would work as well as auto&&. But when the loop was sometimes handling non-proxy references and sometimes proxy-references, then I think auto&& would become the solution of choice.
Using auto&& or universal references with a range-based for-loop has the advantage that you captures what you get. For most kinds of iterators you'll probably get either a T& or a T const& for some type T. The interesting case is where dereferencing an iterator yields a temporary: C++ 2011 got relaxed requirements and iterators aren't necessarily required to yield an lvalue. The use of universal references matches the argument forwarding in std::for_each():
template <typename InIt, typename F>
F std::for_each(InIt it, InIt end, F f) {
for (; it != end; ++it) {
f(*it); // <---------------------- here
}
return f;
}
The function object f can treat T&, T const&, and T differently. Why should the body of a range-based for-loop be different? Of course, to actually take advantage of having deduced the type using universal references you'd need to pass them on correspondingly:
for (auto&& x: range) {
f(std::forward<decltype(x)>(x));
}
Of course, using std::forward() means that you accept any returned values to be moved from. Whether objects like this makes much sense in non-template code I don't know (yet?). I can imagine that using universal references can offer more information to the compiler to do the Right Thing. In templated code it stays out of making any decision on what should happen with the objects.
I virtually always use auto&&. Why get bitten by an edge case when you don't have to? It's shorter to type too, and I simply find it more... transparent. When you use auto&& x, then you know that x is exactly *it, every time.
const auto& would suffice if I want to perform read-only operations. However, I have bumped into
for (auto&& e : v) // v is non-const
a couple of times recently. This makes me wonder:
Is it possible that in some obscure corner cases there is some performance benefit in using forwarding references, compared to auto& or const auto&?
(shared_ptr is a suspect for obscure corner cases)
Update
Two examples that I found in my favorites:
Any disadvantage of using const reference when iterating over basic types?
Can I easily iterate over the values of a map using a range-based for loop?
Please concentrate on the question: why would I want to use auto&& in range-based for loops?
The only advantage I can see is when the sequence iterator returns a proxy reference and you need to operate on that reference in a non-const way. For example consider:
#include <vector>
int main()
{
std::vector<bool> v(10);
for (auto& e : v)
e = true;
}
This doesn't compile because rvalue vector<bool>::reference returned from the iterator won't bind to a non-const lvalue reference. But this will work:
#include <vector>
int main()
{
std::vector<bool> v(10);
for (auto&& e : v)
e = true;
}
All that being said, I wouldn't code this way unless you knew you needed to satisfy such a use case. I.e. I wouldn't do this gratuitously because it does cause people to wonder what you're up to. And if I did do it, it wouldn't hurt to include a comment as to why:
#include <vector>
int main()
{
std::vector<bool> v(10);
// using auto&& so that I can handle the rvalue reference
// returned for the vector<bool> case
for (auto&& e : v)
e = true;
}
Edit
This last case of mine should really be a template to make sense. If you know the loop is always handling a proxy reference, then auto would work as well as auto&&. But when the loop was sometimes handling non-proxy references and sometimes proxy-references, then I think auto&& would become the solution of choice.
Using auto&& or universal references with a range-based for-loop has the advantage that you captures what you get. For most kinds of iterators you'll probably get either a T& or a T const& for some type T. The interesting case is where dereferencing an iterator yields a temporary: C++ 2011 got relaxed requirements and iterators aren't necessarily required to yield an lvalue. The use of universal references matches the argument forwarding in std::for_each():
template <typename InIt, typename F>
F std::for_each(InIt it, InIt end, F f) {
for (; it != end; ++it) {
f(*it); // <---------------------- here
}
return f;
}
The function object f can treat T&, T const&, and T differently. Why should the body of a range-based for-loop be different? Of course, to actually take advantage of having deduced the type using universal references you'd need to pass them on correspondingly:
for (auto&& x: range) {
f(std::forward<decltype(x)>(x));
}
Of course, using std::forward() means that you accept any returned values to be moved from. Whether objects like this makes much sense in non-template code I don't know (yet?). I can imagine that using universal references can offer more information to the compiler to do the Right Thing. In templated code it stays out of making any decision on what should happen with the objects.
I virtually always use auto&&. Why get bitten by an edge case when you don't have to? It's shorter to type too, and I simply find it more... transparent. When you use auto&& x, then you know that x is exactly *it, every time.
const auto& would suffice if I want to perform read-only operations. However, I have bumped into
for (auto&& e : v) // v is non-const
a couple of times recently. This makes me wonder:
Is it possible that in some obscure corner cases there is some performance benefit in using forwarding references, compared to auto& or const auto&?
(shared_ptr is a suspect for obscure corner cases)
Update
Two examples that I found in my favorites:
Any disadvantage of using const reference when iterating over basic types?
Can I easily iterate over the values of a map using a range-based for loop?
Please concentrate on the question: why would I want to use auto&& in range-based for loops?
The only advantage I can see is when the sequence iterator returns a proxy reference and you need to operate on that reference in a non-const way. For example consider:
#include <vector>
int main()
{
std::vector<bool> v(10);
for (auto& e : v)
e = true;
}
This doesn't compile because rvalue vector<bool>::reference returned from the iterator won't bind to a non-const lvalue reference. But this will work:
#include <vector>
int main()
{
std::vector<bool> v(10);
for (auto&& e : v)
e = true;
}
All that being said, I wouldn't code this way unless you knew you needed to satisfy such a use case. I.e. I wouldn't do this gratuitously because it does cause people to wonder what you're up to. And if I did do it, it wouldn't hurt to include a comment as to why:
#include <vector>
int main()
{
std::vector<bool> v(10);
// using auto&& so that I can handle the rvalue reference
// returned for the vector<bool> case
for (auto&& e : v)
e = true;
}
Edit
This last case of mine should really be a template to make sense. If you know the loop is always handling a proxy reference, then auto would work as well as auto&&. But when the loop was sometimes handling non-proxy references and sometimes proxy-references, then I think auto&& would become the solution of choice.
Using auto&& or universal references with a range-based for-loop has the advantage that you captures what you get. For most kinds of iterators you'll probably get either a T& or a T const& for some type T. The interesting case is where dereferencing an iterator yields a temporary: C++ 2011 got relaxed requirements and iterators aren't necessarily required to yield an lvalue. The use of universal references matches the argument forwarding in std::for_each():
template <typename InIt, typename F>
F std::for_each(InIt it, InIt end, F f) {
for (; it != end; ++it) {
f(*it); // <---------------------- here
}
return f;
}
The function object f can treat T&, T const&, and T differently. Why should the body of a range-based for-loop be different? Of course, to actually take advantage of having deduced the type using universal references you'd need to pass them on correspondingly:
for (auto&& x: range) {
f(std::forward<decltype(x)>(x));
}
Of course, using std::forward() means that you accept any returned values to be moved from. Whether objects like this makes much sense in non-template code I don't know (yet?). I can imagine that using universal references can offer more information to the compiler to do the Right Thing. In templated code it stays out of making any decision on what should happen with the objects.
I virtually always use auto&&. Why get bitten by an edge case when you don't have to? It's shorter to type too, and I simply find it more... transparent. When you use auto&& x, then you know that x is exactly *it, every time.
const auto& would suffice if I want to perform read-only operations. However, I have bumped into
for (auto&& e : v) // v is non-const
a couple of times recently. This makes me wonder:
Is it possible that in some obscure corner cases there is some performance benefit in using forwarding references, compared to auto& or const auto&?
(shared_ptr is a suspect for obscure corner cases)
Update
Two examples that I found in my favorites:
Any disadvantage of using const reference when iterating over basic types?
Can I easily iterate over the values of a map using a range-based for loop?
Please concentrate on the question: why would I want to use auto&& in range-based for loops?
The only advantage I can see is when the sequence iterator returns a proxy reference and you need to operate on that reference in a non-const way. For example consider:
#include <vector>
int main()
{
std::vector<bool> v(10);
for (auto& e : v)
e = true;
}
This doesn't compile because rvalue vector<bool>::reference returned from the iterator won't bind to a non-const lvalue reference. But this will work:
#include <vector>
int main()
{
std::vector<bool> v(10);
for (auto&& e : v)
e = true;
}
All that being said, I wouldn't code this way unless you knew you needed to satisfy such a use case. I.e. I wouldn't do this gratuitously because it does cause people to wonder what you're up to. And if I did do it, it wouldn't hurt to include a comment as to why:
#include <vector>
int main()
{
std::vector<bool> v(10);
// using auto&& so that I can handle the rvalue reference
// returned for the vector<bool> case
for (auto&& e : v)
e = true;
}
Edit
This last case of mine should really be a template to make sense. If you know the loop is always handling a proxy reference, then auto would work as well as auto&&. But when the loop was sometimes handling non-proxy references and sometimes proxy-references, then I think auto&& would become the solution of choice.
Using auto&& or universal references with a range-based for-loop has the advantage that you captures what you get. For most kinds of iterators you'll probably get either a T& or a T const& for some type T. The interesting case is where dereferencing an iterator yields a temporary: C++ 2011 got relaxed requirements and iterators aren't necessarily required to yield an lvalue. The use of universal references matches the argument forwarding in std::for_each():
template <typename InIt, typename F>
F std::for_each(InIt it, InIt end, F f) {
for (; it != end; ++it) {
f(*it); // <---------------------- here
}
return f;
}
The function object f can treat T&, T const&, and T differently. Why should the body of a range-based for-loop be different? Of course, to actually take advantage of having deduced the type using universal references you'd need to pass them on correspondingly:
for (auto&& x: range) {
f(std::forward<decltype(x)>(x));
}
Of course, using std::forward() means that you accept any returned values to be moved from. Whether objects like this makes much sense in non-template code I don't know (yet?). I can imagine that using universal references can offer more information to the compiler to do the Right Thing. In templated code it stays out of making any decision on what should happen with the objects.
I virtually always use auto&&. Why get bitten by an edge case when you don't have to? It's shorter to type too, and I simply find it more... transparent. When you use auto&& x, then you know that x is exactly *it, every time.