You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

《Effective Modern C++》示例中索引运算符前使用std::forward的原因

不过我们需要更新该模板的实现,以符合第25条提出的对万能引用应用std::forward的建议:

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

问题1:调用索引运算符时使用std::forward能带来什么收益?

这里的收益核心是保障泛型代码的通用性和正确性,不是针对所有容器都立刻能看到效果,而是适配所有符合语法规则的容器实现:

  • C++允许类的成员函数加引用限定符,operator[]作为成员函数也可以针对左值实例、右值实例提供不同的重载,返回不同的值类别。比如下面的自定义容器:
    class CustomContainer {
    private:
        std::vector<int> data = {1,2,3};
    public:
        // 左值容器调用时返回左值引用
        int& operator[](size_t idx) & {
            return data[idx];
        }
        // 右值容器调用时返回右值引用
        int&& operator[](size_t idx) && {
            return std::move(data[idx]);
        }
    };
    
  • 如果你不对c做std::forward,不管传入的c原始是左值还是右值,c作为函数内的左值变量,永远只会调用左值版本的operator[],直接丢失了右值容器的重载匹配能力。只有用std::forward<Container>(c)保留c的原始值类别,才能正确匹配到对应重载。
  • 配合返回值的decltype(auto),可以把operator[]返回的值类别原封不动传递给调用方:如果传入的是右值容器且operator[]返回右值引用,调用方就可以直接对返回值做移动构造,避免拷贝开销。

问题2:为什么测试代码里用了std::forward还是没有返回右值引用?

你的测试代码没有看到效果,是因为你用的std::vector的operator[]没有提供带右值引用限定的重载。标准委员会没有为std::vector加这个重载,核心是为了避免悬空引用的安全问题(比如临时vector返回的元素引用很容易在vector销毁后变成野引用),但这不代表std::forward在这里没用:

  • 你把测试代码里的std::vector<int>替换成上面的CustomContainer,就能看到明显区别:
    template<typename T>
    void f2(T && param) {
        f1(param[0]);  // 永远调用f1(int &)
        f1(std::forward<T>(param)[0]); // 传入右值CustomContainer时调用f1(int &&)
    }
    
    int main()
    {
        f2(CustomContainer{}); // 传入右值自定义容器
        return 0;
    }
    
    运行后会打印:
    f1 called for int &
    f1 called for int &&
    
  • 你的测试结论只适用于std::vector这类没有右值版本operator[]的容器,而authAndAccess是通用模板,需要兼容所有可能的容器实现,包括标准库后续新增的容器、业务代码里的自定义容器,因此必须加std::forward保证语义正确。

内容的提问来源于stack exchange,提问作者not_that_guy123

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 09:27:02