【问题标题】:How do you comprehend "std: :forward is just syntactic sugar"? Is that true?您如何理解“std: :forward 只是语法糖”?真的吗?
【发布时间】:2020-10-03 15:03:28
【问题描述】:

您如何理解“std::forward 只是语法糖”?真的吗?如果您能详细解释下面的相关代码,我将不胜感激。

根据文档(https://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a00416_source.html), 这里是std::forward的实现:

    /**
    *  @brief  Forward an lvalue.
    *  @return The parameter cast to the specified type.
    *
    *  This function is used to implement "perfect forwarding".
    */
   template<typename _Tp>
     constexpr _Tp&&
     forward(typename std::remove_reference<_Tp>::type& __t) noexcept
     { return static_cast<_Tp&&>(__t); }



  /**
    *  @brief  Forward an rvalue.
    *  @return The parameter cast to the specified type.
    *
    *  This function is used to implement "perfect forwarding".
    */
   template<typename _Tp>
     constexpr _Tp&&
     forward(typename std::remove_reference<_Tp>::type&& __t) noexcept
     {
       static_assert(!std::is_lvalue_reference<_Tp>::value, "template argument"
                     " substituting _Tp is an lvalue reference type");
       return static_cast<_Tp&&>(__t);
     }
    /**
    *  @brief  Convert a value to an rvalue.
    *  @param  __t  A thing of arbitrary type.
    *  @return The parameter cast to an rvalue-reference to allow moving it.
   */
   template<typename _Tp>
     constexpr typename std::remove_reference<_Tp>::type&&
     move(_Tp&& __t) noexcept
     { return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); }

【问题讨论】:

  • 阅读 scott meyers “有效的现代 c++” - 深入了解移动和前进,它们只是演员表
  • “语法糖”是指一种语言特性,它不添加功能,而只是为了使代码更易于阅读和理解。 (这可能是 Mary Poppins 的参考,即“一勺糖使药物下降”)
  • 如您所见,std::forward 是一个简单的静态转换。
  • 你对“syntactic sugar”这个词的理解是什么?
  • @ThomasSablik 很高兴再次见到您!这是真的吗?我完全理解这是昨天在您的帮助下进行的类型转换。我确实见过很多这样的说法。

标签: c++ c++11 c++14 perfect-forwarding syntactic-sugar


【解决方案1】:

“std: :forward 只是语法糖”?这是真的吗?

取决于“只是语法糖”的含义。

您如何理解“std::forward 只是语法糖”?

我认为描述std::forward的正确和类似的方式是它是一个非常简单的函数模板,可以用标准C++实现。

换句话说,在标准库中提供std::forward对于程序员进行完美转发不是必需的。

【讨论】:

    【解决方案2】:

    似乎实际的问题是:“std::forward 做了什么,为什么有必要?”

    std::forward 可以称为static_cast 的语法糖。通常(可能总是)它只做一个演员表。它将函数的参数分别转换为 r 值。 l 值参考,这在许多情况下是必要的,例如:

    #include <iostream>
    
    void f(int &) {
        std::cout << "L-value reference\n";
    }
    
    void f(int &&) {
        std::cout << "R-value reference\n";
    }
    
    template<typename T>
    void g(T &&a) {
        f(a);
    }
    
    template<typename T>
    void h(T &&a) {
        f(std::forward<T>(a));
    }
    
    template<typename T>
    void i(T &&a) {
        f(static_cast<T&&>(a));
    }
    
    int main() {
        int a = 5;
        g(a);
        g(5);
        h(a);
        h(5);
        i(a);
        i(5);
    }
    

    打印

    L-value reference
    L-value reference
    L-value reference
    R-value reference
    L-value reference
    R-value reference
    

    函数调用g(5) 调用f(int &amp;)。这通常不是预期的。

    这是因为所有函数参数都是左值。它们有一个名字,可以取它的地址并赋值,例如:

    #include <iostream>
    
    void f(int &) {
        std::cout << " L-value reference\n";
    }
    
    void f(int &&) {
        std::cout << " R-value reference\n";
    }
    
    void j(int &&a) {
        std::cout << &a;
        a = 6;
        f(a);
    }
    
    void k(int &&a) {
        std::cout << &a;
        a = 6;
        f(std::forward<int>(a));
    }
    
    int main() {
        j(5);
        k(5);
    }
    

    打印

    0x7ffc2db04ea8 L-value reference
    0x7ffc2db04eac R-value reference
    

    【讨论】:

    • @John 你应该只问一个问题。 Stackoverflow 不是一个讨论平台。你可以找到你的答案here
    【解决方案3】:

    我理解这个问题的精神,但是,我不同意它的前提。

    由于 std::forward 可以使用标准 C++ 的语法来实现,它不是通常所说的“语法糖”;也就是说,std::forward 的实现不需要向语言中添加新的语法。 “语法糖”是语言设计者添加的新语法,以提供一种不太冗长的方式来表达所需的行为,尽管如此,使用该语言仍然可以表达。 (如果它以前不能表达,那么它就不是语法糖;它是一种新的语言特性)

    在 C++11 中确实添加了实际的语法糖。基于范围的 for 循环是语法糖。

    不管怎样,至于问题的精神,要理解std::forward的实现,你需要明白两件事

    1. C++ 的引用折叠规则
    2. “转发引用”与 R 值引用不同的一般概念 - Scott Meyers 称之为“通用引用”。

    【讨论】:

    • 感谢您的澄清。还有一个问题,在推导 int a;f(a) 时哪个语句是正确的:“因为 a 是左值,所以 int(T&amp;&amp;) 等于 int(int&amp; &amp;&amp;)”或“使 T&amp;&amp; 等于 int&amp;,所以 T 应该是 @ 987654326@"?我更喜欢后者。
    猜你喜欢
    • 2011-03-08
    • 2011-03-09
    • 1970-01-01
    • 2022-11-29
    • 1970-01-01
    • 1970-01-01
    • 2020-07-24
    • 2018-02-20
    • 2013-11-28
    相关资源
    最近更新 更多