C++ 新特性 | C++ 11 | std::forward、万能引用与完美转发

发布时间:2024年01月24日


概述

std::forward是C++11中引入的一个函数模板,用于实现完美转发。它的作用是根据传入的参数,决定将参数以左值引用还是右值引用的方式进行转发。

传统上,当一个左值传递给一个函数时,参数会以左值引用的方式进行传递;当一个右值传递给一个函数时,参数会以右值引用的方式进行传递。完美转发是为了解决传递参数时的临时对象(右值)被强制转换为左值的问题。std::forward实现完美转发主要用于以下场景:提高模板函数参数传递过程的转发效率

一、std::forward、万能引用与完美转发

1、引用折叠

C++引用折叠是一种特性,允许在模板元编程中使用引用类型的参数来创建新的引用类型。由于存在T&&这种万能引用类型,当它作为参数时,有可能被一个左值引用或右值引用的参数初始化,这是经过类型推导的T&&类型,推导后得到的参数类型会发生类型变化,这种变化就称为引用折叠。

根本原因是因为C++中禁止reference to reference,所以编译器需要对四种情况(& && &&&& &,&& &&)进行处理,将他们折叠成一种单一的reference。引用折叠的规则如下:如果两个引用中至少其中一个引用是左值引用,那么折叠结果就是左值引用;否则折叠结果就是右值引用。示例如下:

using T = int &;
T& r1;  // int& & r1 -> int& r1
T&& r2; // int& && r2 -> int& r2
  
using U = int &&;
U& r3;  // int&& & r3 -> int& r3
U&& r4; // int&& && r4 -> int&& r4

下面是一个具体的示例,可以看下对应的推导过程

template<typename T>
void fun(T &&t) {
    cout << "hello world" << endl;
}

int main() {
    int a = 1;
    int &b = a;
    fun(a); // T 推导成 int &; T && ==> int & && ==> int &
    fun(1); // T 推导成 int &&; T && ==> int && && ==> int &&
    fun(b); // T 推导成 int &; T && ==> int & && ==> int &
    return 0;
}

注意:只有当发生自动类型推断时(例如:函数模板的类型自动推导),&&才是一个universal references。下面一个示例中的&& 并不是一个references,例如:

template<typename T>
void f( T&& param); // 这里T的类型需要推导,所以&&是一个 universal references

template<typename T>
class Test {
	Test(Test&& rhs);  // Test是一个特定的类型,不需要类型推导,所以&&表示右值引用  
};

2、std::remove_reference

std::remove_reference是一个类型提取器,实现的功能比较简单,通过模版提取出最底层类型,提取出来的底层类型保存在std::remove_reference::type,示例:通过下面的代码可以看出,通过类型提取器,可以从int &int && 中分离出最底层的int

#include <iostream>
#include <type_traits>
using namespace std;

int main() {
    int i = 10;
    int &ref = i;

    std::remove_reference<decltype((i))>::type a = 10;           // 左值
    std::remove_reference<decltype(200)>::type b = 10;           // 右值
    std::remove_reference<decltype((ref))>::type c = 10;         // 左值引用
    std::remove_reference<decltype(std::move(i))>::type d = 10;  // 右值引用

    std::cout << std::is_same<int, std::remove_reference<decltype((i))>::type>::value << std::endl;
    std::cout << std::is_same<int, std::remove_reference<decltype(200)>::type>::value << std::endl;
    std::cout << std::is_same<int, std::remove_reference<decltype((ref))>::type>::value << std::endl;
    std::cout << std::is_same<int, std::remove_reference<decltype(std::move(i))>::type>::value << std::endl;

    return 0;
}

输出结果

1
1
1
1

https://zhuanlan.zhihu.com/p/580797507
https://www.zhihu.com/question/40346748/answer/88672920

文章来源:https://blog.csdn.net/cloud323/article/details/135824374
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。