사용하여 auto&& var = <initializer>
: 당신이 말을 내가 관계없이 좌변 또는를 rvalue 표현인지의 이니셜을 수락하고 나는 그것의 const와 보존됩니다 . 일반적으로 전달하는 데 사용됩니다 (일반적으로와 함께 T&&
). 는 "보편적 참조"때문에이 작품 이유는 auto&&
나 T&&
에 바인딩 아무것도 .
당신은 말할 수도 있습니다. const auto&
왜냐하면 그것이 무엇 에도 바인딩 될 것이기 때문에 왜 사용하지 않습니까? const
참조 를 사용할 때의 문제 는 그것이 참조라는 것입니다 const
! 나중에 비 const 참조에 바인딩하거나 표시되지 않은 멤버 함수를 호출 할 수 없습니다 const
.
예를 들어,을 가져 std::vector
오고 반복자를 첫 번째 요소로 가져 와서 반복자가 가리키는 값을 어떤 방식으로 수정한다고 가정하십시오.
auto&& vec = some_expression_that_may_be_rvalue_or_lvalue;
auto i = std::begin(vec);
(*i)++;
이 코드는 이니셜 라이저 표현식에 관계없이 잘 컴파일됩니다. auto&&
다음과 같은 방법으로 실패 할 수있는 대안 :
auto => will copy the vector, but we wanted a reference
auto& => will only bind to modifiable lvalues
const auto& => will bind to anything but make it const, giving us const_iterator
const auto&& => will bind only to rvalues
이를 위해 auto&&
완벽하게 작동합니다! auto&&
이와 같이 사용하는 예는 범위 기반 for
루프에 있습니다. 자세한 내용은 다른 질문 을 참조하십시오.
그런 다음 사용하는 경우 std::forward
사용자에 auto&&
원래 좌변 또는를 rvalue 중 하나라는 사실을 보존하기 위해 참조 코드는 말합니다 : 지금은 좌변 또는를 rvalue 표현 중 하나에서 개체를 가지고 있음을, 내가 원래 그것을 valueness 중 보존 할 내가 가장 효율적으로 사용할 수 있도록 했으므로 무효가 될 수 있습니다. 에서처럼 :
auto&& var = some_expression_that_may_be_rvalue_or_lvalue;
// var was initialized with either an lvalue or rvalue, but var itself
// is an lvalue because named rvalues are lvalues
use_it_elsewhere(std::forward<decltype(var)>(var));
이렇게하면 use_it_elsewhere
원래 이니셜 라이저가 수정 가능한 rvalue 일 때 성능을 위해 (복사를 피하기 위해) 내장을 제거 할 수 있습니다.
우리가 언제 자원을 훔칠 수 있는지에 대한 의미는 무엇입니까 var
? auto&&
의지가 무엇이든 구속력이 있기 때문에 , 우리는 아마도 var
자신의 용기 를 찢어 버릴 수는 없습니다. 그것은 아주 가치가 있거나 구성 요소 일 수도 있습니다. 그러나 std::forward
내부를 완전히 손상시킬 수있는 다른 기능에 대해서도 가능합니다. 이 작업을 수행하자마자 var
잘못된 상태에있는 것으로 간주 해야합니다.
이제 auto&& var = foo();
질문에 주어진 것처럼 foo T
를 값으로 반환 합니다. 이 경우 우리는의 유형 var
이로 추론 됨을 확실히 알고 있습니다 T&&
. 우리는 그것이 rvalue라는 것을 확실히 알고 있기 때문에 우리 std::forward
는 자원을 훔칠 수있는 권한이 필요하지 않습니다 . 이 특정한 경우에, 그 아는 foo
값으로 반환 :로, 독자는 그것을 읽어야 내가로부터 돌려 임시로를 rvalue 참조 데려 갈거야 foo
내가 행복하게에서 이동할 수 있습니다.
부록으로서, some_expression_that_may_be_rvalue_or_lvalue
"코드가 잘 변경 될 수있는"상황 이외 의 표현이 나타날 때 언급 할 가치가 있다고 생각합니다 . 다음은 좋은 예입니다.
std::vector<int> global_vec{1, 2, 3, 4};
template <typename T>
T get_vector()
{
return global_vec;
}
template <typename T>
void foo()
{
auto&& vec = get_vector<T>();
auto i = std::begin(vec);
(*i)++;
std::cout << vec[0] << std::endl;
}
여기 get_vector<T>()
에 제네릭 형식에 따라 lvalue 또는 rvalue가 될 수있는 멋진 표현이 있습니다 T
. 기본적으로 get_vector
의 템플릿 매개 변수를 통해 반환 유형을 변경합니다 foo
.
우리가 호출 할 때 foo<std::vector<int>>
, get_vector
리턴 global_vec
를 rvalue 식을 제공 값에 의해. 또는를 호출 foo<std::vector<int>&>
하면 참조로 get_vector
반환 global_vec
되어 lvalue 표현식이 생성됩니다.
우리가 할 경우 :
foo<std::vector<int>>();
std::cout << global_vec[0] << std::endl;
foo<std::vector<int>&>();
std::cout << global_vec[0] << std::endl;
예상대로 다음과 같은 결과가 나타납니다.
2
1
2
2
당신이를 변경한다면 auto&&
어떤에 코드에서 auto
, auto&
, const auto&
, 또는 const auto&&
우리는 우리가 원하는 결과를 얻을 수 없습니다.
auto&&
참조가 lvalue 또는 rvalue 표현식으로 초기화 되는지 여부에 따라 프로그램 논리를 변경하는 다른 방법 은 유형 특성을 사용하는 것입니다.
if (std::is_lvalue_reference<decltype(var)>::value) {
// var was initialised with an lvalue expression
} else if (std::is_rvalue_reference<decltype(var)>::value) {
// var was initialised with an rvalue expression
}
auto&&
합니까? 범위 기반 for 루프auto&&
가 예제 로 사용하기 위해 확장되는 이유를 생각해 보았지만 그 범위로 돌아 가지 않았습니다. 아마도 대답하는 사람이 그것을 설명 할 수 있습니다.