c++ - 在“Effective Modern C++”示例中索引运算符之前使用 std::forward 的原因
问题描述
引用“Effective Modern C++”的第 3 项(“了解 decltype”):
然而,我们需要更新模板的实现以使其符合条款 25 的劝告,将 std::forward 应用于通用引用:
template<typename Container, typename Index>
decltype(auto) authAndAccess(Container&& c, Index i)
{
authenticateUser();
return std::forward<Container>(c)[i];
}
为什么我们在“authAndAccess”的最后一条语句中转发“c”?我理解当我们将参数从原始函数中传递给另一个函数时需要转发(以便能够正确调用采用右值引用的重载版本,或者如果存在按值获取参数的重载版本,那么我们可以移动而不是复制),但是在上面的例子中调用 indexing-operator 时 std::forward 给我们带来了什么好处?
下面的示例还验证了使用 std::forward 不允许我们从 authAndAccess 返回右值引用,例如,如果我们希望能够使用返回值移动(而不是复制)。
#include <bits/stdc++.h>
void f1(int & param1) {
std::cout << "f1 called for int &\n";
}
void f1(int && param1) {
std::cout << "f1 called for int &&\n";
}
template<typename T>
void f2(T && param) {
f1(param[0]); // calls f1(int & param1)
f1(std::forward<T>(param)[0]); // also calls f1(int & param1) as [] returns an lvalue reference
}
int main()
{
std::vector<int> vec1{1, 5, 9};
f2(std::move(vec1));
return 0;
}
解决方案
这取决于容器是如何实现的。如果它有两个左值和右值的引用限定 operator[]
,例如
T& operator[] (std::size_t) &; // used when called on lvalue
T operator[] (std::size_t) &&; // used when called on rvalue
然后
template<typename Container, typename Index>
decltype(auto) authAndAccess(Container&& c, Index i)
{
authenticateUser();
return std::forward<Container>(c)[i]; // call the 1st overload when lvalue passed; return type is T&
// call the 2nd overload when rvalue passed; return type is T
}
如果不转发引用,可能会导致麻烦。
template<typename Container, typename Index>
decltype(auto) authAndAccess(Container&& c, Index i)
{
authenticateUser();
return c[i]; // always call the 1st overload; return type is T&
}
然后
const T& rt = authAndAccess(Container{1, 5, 9}, 0);
// dangerous; rt is dangling
顺便说一句,这不起作用,std::vector
因为它没有引用限定的operator[]
重载。
推荐阅读
- excel - PowerPivot 和 Excel 行级安全性 - 此解决方案的安全性如何?
- java - 如何找到我的类用作某个实现接口的用法?
- python - Tensorflow 混合两种多元分布
- ruby - 通过数据包进行厨师延迟属性分配
- java - 为什么 Eclipse m2e 不自动将生成的源文件夹添加到类路径?
- c# - 没有为实体类型 MyImage 找到合适的构造函数
- javascript - 我无法获得特定的网址
- ansible - 如何强制 Ansible 使用 sudo 安装包?
- javascript - 通过 JavaScript 拦截所有网络流量
- javascript - 使用 .reduce() 对数据结果进行分组