• C++11中std::forward的使用 (转)


    std::forward argument: Returns an rvalue reference to arg if arg is not an lvalue reference; If arg is an lvalue reference, the function returns arg without modifying its type.

    std::forward:This is a helper function to allow perfect forwarding of arguments taken as rvalue references to deduced types, preserving any potential move semantics involved. 

    std::forward<T>(u)有两个参数:T 与 u。当T为左值引用类型时,u将被转换为T类型的左值,否则u将被转换为T类型右值。如此定义std::forward是为了在使用右值引用参数的函数模板中解决参数的完美转发问题。

    std::move是无条件的转为右值引用,而std::forward是有条件的转为右值引用,更准确的说叫做Perfect forwarding(完美转发),而std::forward里面蕴含着的条件则是Reference Collapsing(引用折叠)。

    std::move不move任何东西。std::forward也不转发任何东西。在运行时,他们什么都不做。不产生可执行代码,一个比特的代码也不产生。

    std::move和std::forward只是执行转换的函数(确切的说应该是函数模板)。std::move无条件的将它的参数转换成一个右值,而std::forward当特定的条件满足时,才会执行它的转换。

    std::move表现为无条件的右值转换,就其本身而已,它不会移动任何东西。 std::forward仅当参数被右值绑定时,才会把参数转换为右值。 std::move和std::forward在运行时不做任何事情。

    下面是从其他文章中copy的测试代码,详细内容介绍可以参考对应的reference:

    1. #include "forward.hpp"  
    2. #include <utility>  
    3. #include <iostream>  
    4. #include <memory>  
    5. #include <string>  
    6.   
    7. //////////////////////////////////////////////  
    8. // reference: http://en.cppreference.com/w/cpp/utility/forward  
    9. struct A {  
    10.     A(int&& n) { std::cout << "rvalue overload, n=" << n << " "; }  
    11.     A(int& n)  { std::cout << "lvalue overload, n=" << n << " "; }  
    12. };  
    13.   
    14. class B {  
    15. public:  
    16.     template<class T1, class T2, class T3>  
    17.     B(T1&& t1, T2&& t2, T3&& t3) :  
    18.         a1_{ std::forward<T1>(t1) },  
    19.         a2_{ std::forward<T2>(t2) },  
    20.         a3_{ std::forward<T3>(t3) }  
    21.     {  
    22.     }  
    23.   
    24. private:  
    25.     A a1_, a2_, a3_;  
    26. };  
    27.   
    28. template<class T, class U>  
    29. std::unique_ptr<T> make_unique1(U&& u)  
    30. {  
    31.     return std::unique_ptr<T>(new T(std::forward<U>(u)));  
    32. }  
    33.   
    34. template<class T, class... U>  
    35. std::unique_ptr<T> make_unique(U&&... u)  
    36. {  
    37.     return std::unique_ptr<T>(new T(std::forward<U>(u)...));  
    38. }  
    39.   
    40. int test_forward1()  
    41. {  
    42.     auto p1 = make_unique1<A>(2); // rvalue  
    43.     int i = 1;  
    44.     auto p2 = make_unique1<A>(i); // lvalue  
    45.   
    46.     std::cout << "B ";  
    47.     auto t = make_unique<B>(2, i, 3);  
    48.   
    49.     return 0;  
    50. }  
    51.   
    52. ////////////////////////////////////////////////////////  
    53. // reference: http://www.cplusplus.com/reference/utility/forward/  
    54. // function with lvalue and rvalue reference overloads:  
    55. void overloaded(const int& x) { std::cout << "[lvalue]"; }  
    56. void overloaded(int&& x) { std::cout << "[rvalue]"; }  
    57.   
    58. // function template taking rvalue reference to deduced type:  
    59. template <class T> void fn(T&& x) {  
    60.     overloaded(x);                   // always an lvalue  
    61.     overloaded(std::forward<T>(x));  // rvalue if argument is rvalue  
    62. }  
    63.   
    64. int test_forward2()  
    65. {  
    66.     int a;  
    67.   
    68.     std::cout << "calling fn with lvalue: ";  
    69.     fn(a);  
    70.     std::cout << ' ';  
    71.   
    72.     std::cout << "calling fn with rvalue: ";  
    73.     fn(0);  
    74.     std::cout << ' ';  
    75.   
    76.     return 0;  
    77. }  
    78.   
    79. //////////////////////////////////////////////////////  
    80. // reference: http://stackoverflow.com/questions/8526598/how-does-stdforward-work  
    81. template<class T>  
    82. struct some_struct{  
    83.     T _v;  
    84.     template<class U>  
    85.     some_struct(U&& v) : _v(static_cast<U&&>(v)) {} // perfect forwarding here  
    86.     // std::forward is just syntactic sugar for this  
    87. };  
    88.   
    89. int test_forward3()  
    90. {  
    91.     /* remember the reference collapsing rules(引用折叠规则): 
    92.     前者代表接受类型,后者代表进入类型,=>表示引用折叠之后的类型,即最后被推导决断的类型 
    93.     TR   R 
    94.  
    95.     T&   &->T&   // lvalue reference to cv TR -> lvalue reference to T 
    96.     T&   &&->T&  // rvalue reference to cv TR -> TR (lvalue reference to T) 
    97.     T&&  &->T&   // lvalue reference to cv TR -> lvalue reference to T 
    98.     T&&  &&->T&& // rvalue reference to cv TR -> TR (rvalue reference to T) */  
    99.   
    100.     some_struct<int> s1(5);  
    101.     // in ctor: '5' is rvalue (int&&), so 'U' is deduced as 'int', giving 'int&&'  
    102.     // ctor after deduction: 'some_struct(int&& v)' ('U' == 'int')  
    103.     // with rvalue reference 'v' bound to rvalue '5'  
    104.     // now we 'static_cast' 'v' to 'U&&', giving 'static_cast<int&&>(v)'  
    105.     // this just turns 'v' back into an rvalue  
    106.     // (named rvalue references, 'v' in this case, are lvalues)  
    107.     // huzzah, we forwarded an rvalue to the constructor of '_v'!  
    108.   
    109.     // attention, real magic happens here  
    110.     int i = 5;  
    111.     some_struct<int> s2(i);  
    112.     // in ctor: 'i' is an lvalue ('int&'), so 'U' is deduced as 'int&', giving 'int& &&'  
    113.     // applying the reference collapsing rules yields 'int&' (& + && -> &)  
    114.     // ctor after deduction and collapsing: 'some_struct(int& v)' ('U' == 'int&')  
    115.     // with lvalue reference 'v' bound to lvalue 'i'  
    116.     // now we 'static_cast' 'v' to 'U&&', giving 'static_cast<int& &&>(v)'  
    117.     // after collapsing rules: 'static_cast<int&>(v)'  
    118.     // this is a no-op, 'v' is already 'int&'  
    119.     // huzzah, we forwarded an lvalue to the constructor of '_v'!  
    120.   
    121.     return 0;  
    122. }  
    123.   
    124. ////////////////////////////////////////////////////  
    125. // reference: https://oopscenities.net/2014/02/01/c11-perfect-forwarding/  
    126. void sum(int a, int b)  
    127. {  
    128.     std::cout << a + b << std::endl;  
    129. }  
    130.   
    131. void concat(const std::string& a, const std::string& b)  
    132. {  
    133.     std::cout<< a + b << std::endl;  
    134. }  
    135.   
    136. void successor(int a, int& b)  
    137. {  
    138.     b = ++a;  
    139. }  
    140.   
    141. template <typename PROC, typename A, typename B>  
    142. void invoke(PROC p, A&& a, B&& b)  
    143. {  
    144.     p(std::forward<A>(a), std::forward<B>(b));  
    145. }  
    146.   
    147. int test_forward4()  
    148. {  
    149.     invoke(sum, 10, 20);  
    150.     invoke(concat, "Hello", "world");  
    151.     int s = 0;  
    152.     invoke(successor, 10, s);  
    153.     std::cout << s << std::endl;  
    154.   
    155.     return 0;  
    156. }  


    GitHubhttps://github.com/fengbingchun/Messy_Test

  • 相关阅读:
    day02【Collection、泛型】
    day11 【final、权限、内部类、引用类型】
    day10 【接口、多态】
    day09 【继承、super、this、抽象类】
    day08 【String类、static关键字、Arrays类、Math类】
    Java基本运算符
    Java非访问修饰符
    2020学习Java开发有前途吗?看看资深程序员怎么说
    两年Java后端开发,面试了几十家公司的面试分享
    五种方法创建java对象,你知道几种呢?
  • 原文地址:https://www.cnblogs.com/wangbin/p/7509804.html
Copyright © 2020-2023  润新知