What is the difference between 1 and 2? When what to use?
for (auto i : container){} // 1 for (auto&& i : container){} // 2 When you have an ad type
auto &&x = initializer; then the given rvalue reference &&x is special and is called forwarding reference . If the initializer is an lvalue , then this reference takes the lvalue type of the reference.
From the C ++ standard (Document Number: N4296, 7.1.6.4 auto speci er)
- ... Deduce a value for a function call (14.8.2.1) , where a direct call -initialization.
And further (14.8.2.1 Deducing template arguments from a function cal)
- ... A forward reference reference parameter a cv-unqualified template parameter. If you’re referring to the lion, you’re
What does this mean? This means that the following two declarations will be equivalent.
int x = 0; auto &&r = x; and
int x = 0; auto &r = x; Below is a demo program.
#include <iostream> int main() { { int x = 0; std::cout << "x = " << x << std::endl; auto &&r = x; r = 10; std::cout << "x = " << x << std::endl; } { int x = 0; std::cout << "x = " << x << std::endl; auto &r = x; r = 10; std::cout << "x = " << x << std::endl; } } Its output to the console
x = 0 x = 10 x = 0 x = 10 It also follows that when you deal with a for clause based on a range, and the corresponding iterator returned by the begin function, or the corresponding pointer, after applying the dereference operator returns the lvalue value of the original object (pointers always return the lvalue value after dereference), then you You can change this source object using the forwarding reference declaration.
For example,
#include <iostream> #include <vector> int main() { { int a[] = { 0 }; std::cout << "a[0] = " << a[0] << std::endl; auto &&r = *a; r = 10; std::cout << "a[0] = " << a[0] << std::endl; } { std::vector<int> v(1); std::cout << "v[0] = " << v[0] << std::endl; auto &&r = *v.begin(); r = 10; std::cout << "v[0] = " << v[0] << std::endl; } } The output of the program to the console:
a[0] = 0 a[0] = 10 v[0] = 0 v[0] = 10 Therefore, for example, for standard containers that return a reference to the original object from a dereferenced iterator, two similar for declarations are equivalent
std::vector<int> v { 1, 2, 3, 4, 5 }; for ( auto &&x : v ) x *= 2; and
std::vector<int> v { 1, 2, 3, 4, 5 }; for ( auto &x : v ) x *= 2; Since in both cases there is an inferred type of the variable x as int & .
When is a view declaration used
auto x = initializer; then the type of variable x is inferred from the initializer type specifiers, ignoring references. That is, even if the initializer is a reference type, such as int & , the type of the variable x is int , and therefore you cannot change the original object using this variable. For example,
#include <iostream> #include <vector> int main() { { std::vector<int> v{ 1, 2, 3, 4, 5 }; for (int x : v) std::cout << x << ' '; std::cout << std::endl; for (auto &&x : v) x *= 2; for (int x : v) std::cout << x << ' '; std::cout << std::endl; } std::cout << std::endl; { std::vector<int> v{ 1, 2, 3, 4, 5 }; for (int x : v) std::cout << x << ' '; std::cout << std::endl; for (auto x : v) x *= 2; for (int x : v) std::cout << x << ' '; std::cout << std::endl; } } Compare the output of two code blocks of this program.
1 2 3 4 5 2 4 6 8 10 1 2 3 4 5 1 2 3 4 5 If the forwarding reference initialized by the rvalue value, and not the lvalue value, then the rvalue link will not turn into a lvalue link. This difference is shown below.
#include <iostream> int f() { static int x; return x; } int & g() { static int x; return x; } int main() { { auto &&x = f(); std::cout << "x = " << x << std::endl; x = 10; std::cout << "x = " << x << std::endl; std::cout << "f() = " << f() << std::endl; } std::cout << std::endl; { auto &&x = g(); std::cout << "x = " << x << std::endl; x = 10; std::cout << "x = " << x << std::endl; std::cout << "g() = " << g() << std::endl; } } Output of the program to the console
x = 0 x = 10 f() = 0 x = 0 x = 10 g() = 10 As for the question
When what to use?
it is better to use auto & if you want to change the values in the loop that the link will refer to, or const auto & when you use read-only values. auto makes sense to use for fundamental types, for example, arithmetic types or pointers), when copying an object into a local variable to be created is not a resource-expensive operation and you do not need to change the original objects.
It is necessary to choose, depending on the context, about which you did not mention at all. For example, the following code:
#include <vector> int main() { std::vector<bool> v; for (auto i: v) { } for (auto& i: v) { } // ошибка for (auto&& i: v) { } } will give an error for auto& , because vector<bool> uses an auxiliary reference class, the rvalue object of which cannot be associated with a nonconstant reference. Because of the proxy class, another interesting situation arises, that modification i in the auto and auto&& cycles will behave the same, i.e. change the value stored in the container.
If instead of std::vector<bool> use std::vector<int> , then auto will only allow you to change the local variable , and auto&& (like auto& ) already has the value in the container.
In the first case, the search is by value, i.e. You cannot change items.
In the second case - on the universal link. those. in the second case, you can write a code like:
for (auto&& i : container){ ++i;} for(auto& i... - so why two && ? :) - HarryThere is no difference. The universal reference in the for loop is used so that the code is compatible with containers whose iterator returns the rvalue of the reference.
template<typename C> void interate1(C& container) //Non-const { for(auto& v: container) { //Do something with v } } template<typename C> void iterate2(C& conatiner) { for(auto&& v: container) { //Do soemthign with v } } ... std::vector<bool> v(10); iterate1(v); //Error iterate2(v); //OK Source: https://ru.stackoverflow.com/questions/602986/
All Articles