c++ - 在 "Effective Modern C++"示例中在索引运算符之前使用 std::f

引用“Effective Modern C++”的第 3 项(“理解 decltype”):

However, we need to update the template’s implementation to bring it into accord with Item 25’s admonition to apply std::forward to universal references:

template<typename Container, typename Index>
decltype(auto) authAndAccess(Container&& c, Index i)
{
    authenticateUser();
    return std::forward<Container>(c)[i];
}

为什么我们要在“authAndAccess”的最后一条语句中转发“c”?我理解当我们将参数从原始函数中传递给另一个函数时需要转发(以便能够正确调用采用右值引用的重载版本,或者如果存在按值采用参数的重载版本,那么我们可以移动而不是复制),但是在上面的例子中调用索引运算符时 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;
}

最佳答案

这取决于容器是如何实现的。如果它有两个 reference-qualified 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[] 重载。

关于c++ - 在 "Effective Modern C++"示例中在索引运算符之前使用 std::forward 的原因,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69150510/

相关文章:

c++ - 在 constexpr 分支中使用枚举类值

python - 如何找到中轴的关节和端点

python - Azure Databricks python 命令显示当前集群配置

c - 栈在使用Pthread的多线程程序中是如何工作的?

c# - Parallel.Foreach 和每个产生不同的结果 : Why is my code

docker - 使用 deps.edn 在容器中安装依赖项

c# - 如何在 C# 中使用预处理器指令仅在 Windows 10 上执行一些代码?

c - 有没有办法从未知字节设置/清除位,同时保持所有其他位不变?

flutter - 如何在 flutter 中的行之间写 OR

laravel - Laravel 中的 getClientOriginalExtension()