代码之家  ›  专栏  ›  技术社区  ›  Curious

为什么使用std::forward<T>而不是static\u cast<T&&>

  •  23
  • Curious  · 技术社区  · 7 年前

    template <typename... Args>
    void foo(Args&&... args) { ... }
    

    我经常看到库代码的使用 static_cast<Args&&> 在函数中用于参数转发。通常,这样做的理由是使用 static_cast 避免不必要的模板实例化。

    给定语言的引用折叠和模板演绎规则。我们得到了完美的转发 ,这一说法的证据如下(在误差范围内,我希望答案能有所启发)

    • 当给出参考值时(或为了完整性-没有参考资格,如 this example ),这将折叠引用,使结果为右值。使用的规则是 && && && (规则 1
    • 当给定左值引用时,这会以这样一种方式折叠引用,结果就是左值。这里使用的规则是 & && -&燃气轮机; & (规则 2

    这基本上是 foo() 把论点转发给 bar() std::forward<Args>


    问题- 为什么使用 std::forward 在这种情况下?避免额外的实例化是否有理由打破惯例?

    Howard Hinnant的论文 n2951 标准::转发 应该表现得“正确”。这些是

    1. 应将较少的cv限定表达式转发到较多的cv限定表达式
    2. 不应转发任意类型转换

    (1) 和(2)被证明与 静态投射<参数(&A)&&燃气轮机;


    注:我个人更喜欢使用 ,但我的理由纯粹是我更喜欢遵守惯例。

    3 回复  |  直到 7 年前
        1
  •  9
  •   Oliv    7 年前

    forward 表达意图,使用可能比 static_cast : 考虑了转换,但使用 :

    struct A{
       A(int);
       };
    
    template<class Arg1,class Arg2>
    Arg1&& f(Arg1&& a1,Arg2&& a2){
       return static_cast<Arg1&&>(a2); //  typing error: a1=>a2
       }
    
    template<class Arg1,class Arg2>
    Arg1&& g(Arg1&& a1,Arg2&& a2){
       return forward<Arg1>(a2); //  typing error: a1=>a2
       }
    
    void test(const A a,int i){
       const A& x = f(a,i);//dangling reference
       const A& y = g(a,i);//compilation error
      }
    

    错误消息示例: compiler explorer link


    通常,这样做的理由是使用静态类型转换可以避免不必要的模板实例化。

    编译时间比代码可维护性问题更大吗?编码人员是否应该浪费时间考虑最小化代码中每一行的“不必要的模板实例化”?

      template<class T> void foo(T i){
         foo_1(i),foo_2(i),foo_3(i);
         }
    

    foo_1 , foo_2 , foo_3 是模板,是 foo 向前地

    因此,避免模板实例化爆炸的最佳方法是,对“根”类和“根”函数的参数类型使用动态多态性,然后仅对时间关键型函数使用静态多态性,这些函数实际上位于实例化树的上方。

    所以,在我看来 静态浇铸 向前地

        2
  •  13
  •   P.W    7 年前

    Scott Meyers说 std::forward std::move 主要是为了方便。他甚至说 标准::转发 标准::转发 标准::移动 .


    ...
    我的故事 类似于 标准::移动 ,但鉴于 标准::移动 无条件地把它的论点交给 rvalue , 只有在一定条件下才会这样。 标准::转发 是条件强制转换。它投射到一个 R值 只有当它的参数初始化为 R值 .

    考虑到这两者 标准::移动 归结为铸型,唯一的区别是 标准::移动 总是投,而 标准::转发 只是有时候, 你也许会问我们是否可以免除 标准::移动 标准::转发 到处 标准::转发 我能做到这一切。 没有必要。 当然,这两个函数都不是必需的,因为我们可以在任何地方编写强制类型转换,但我希望我们同意,这将是,嗯,令人恶心。
    ...
    标准::移动 它的优点是方便,减少了出错的可能性,而且更清晰。。。

    对于感兴趣的人,比较 std::forward<T> static_cast<T&&> 在里面 assembly (无任何优化)调用时 lvalue R值 .

        3
  •  5
  •   Ferenc Deak    7 年前

    这是我的2.5美分,不是技术上的美分:事实上今天 std::forward 确实只是一个普通的老人 static_cast<T&&> 标准::转发 成就今日,从此 forward 它不会在任何地方出现任何东西。

    标准::转发 ,仅从理论上讲,没有人会阻止未来的实现者提供 标准::转发 静态投射<T&&&燃气轮机; 静态投射<T&&&燃气轮机; 因为唯一重要的事实是正确的用法和行为 标准::转发

    推荐文章