为什么范围算法将右值引用作为参数
why do ranges algorithms take rvalue reference as argument
如果我以 ranges::fill 算法为例:
https://en.cppreference.com/w/cpp/algorithm/ranges/fill
签名是:
template< class T, ranges::output_range<const T&> R >
constexpr ranges::borrowed_iterator_t<R> fill( R&& r, const T& value );
以及使用示例:
#include <algorithm>
#include <vector>
#include <iostream>
int main()
{
std::vector<int> v{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
namespace ranges = std::ranges;
ranges::fill(v, 10);
}
为什么 ranges::fill 将右值引用作为参数 (R&& r)?
我原以为它会采用左值引用 (R& r)。
由于 R
是模板参数,R&&
不是 右值引用 ,而是 forwarding/universal reference.
Forwarding references
Forwarding references are a special kind of references that preserve
the value category of a function argument, making it possible to
forward it by means of std::forward. Forwarding references are either:
function parameter of a function template declared as rvalue
reference to cv-unqualified type template parameter of that same
function template:
template<class T>
int f(T&& x) { // x is a forwarding reference
return g(std::forward<T>(x)); // and so can be forwarded
}
int main() {
int i;
f(i); // argument is lvalue, calls f<int&>(int&), std::forward<int&>(x) is lvalue
f(0); // argument is rvalue, calls f<int>(int&&), std::forward<int>(x) is rvalue
}
template<class T>
int g(const T&& x); // x is not a forwarding reference: const T is not cv-unqualified
template<class T> struct A {
template<class U>
A(T&& x, U&& y, int* p); // x is not a forwarding reference: T is not a
// type template parameter of the constructor,
// but y is a forwarding reference
};
auto&&
except when deduced from a brace-enclosed initializer list:
auto&& vec = foo(); // foo() may be lvalue or rvalue, vec is a forwarding reference
auto i = std::begin(vec); // works either way
(*i)++; // works either way
g(std::forward<decltype(vec)>(vec)); // forwards, preserving value category
for (auto&& x: f()) {
// x is a forwarding reference; this is the safest way to use range for loops
}
auto&& z = {1, 2, 3}; // *not* a forwarding reference (special case for initializer lists)
如果我以 ranges::fill 算法为例:
https://en.cppreference.com/w/cpp/algorithm/ranges/fill
签名是:
template< class T, ranges::output_range<const T&> R >
constexpr ranges::borrowed_iterator_t<R> fill( R&& r, const T& value );
以及使用示例:
#include <algorithm>
#include <vector>
#include <iostream>
int main()
{
std::vector<int> v{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
namespace ranges = std::ranges;
ranges::fill(v, 10);
}
为什么 ranges::fill 将右值引用作为参数 (R&& r)? 我原以为它会采用左值引用 (R& r)。
由于 R
是模板参数,R&&
不是 右值引用 ,而是 forwarding/universal reference.
Forwarding references
Forwarding references are a special kind of references that preserve the value category of a function argument, making it possible to forward it by means of std::forward. Forwarding references are either:
function parameter of a function template declared as rvalue reference to cv-unqualified type template parameter of that same function template:
template<class T> int f(T&& x) { // x is a forwarding reference return g(std::forward<T>(x)); // and so can be forwarded } int main() { int i; f(i); // argument is lvalue, calls f<int&>(int&), std::forward<int&>(x) is lvalue f(0); // argument is rvalue, calls f<int>(int&&), std::forward<int>(x) is rvalue } template<class T> int g(const T&& x); // x is not a forwarding reference: const T is not cv-unqualified template<class T> struct A { template<class U> A(T&& x, U&& y, int* p); // x is not a forwarding reference: T is not a // type template parameter of the constructor, // but y is a forwarding reference };
auto&&
except when deduced from a brace-enclosed initializer list:auto&& vec = foo(); // foo() may be lvalue or rvalue, vec is a forwarding reference auto i = std::begin(vec); // works either way (*i)++; // works either way g(std::forward<decltype(vec)>(vec)); // forwards, preserving value category for (auto&& x: f()) { // x is a forwarding reference; this is the safest way to use range for loops } auto&& z = {1, 2, 3}; // *not* a forwarding reference (special case for initializer lists)