C++迈向精通:模板中的引用与remove_reference原理

remove_reference 原理

模板中的引用参数

在模板中,双 '&‘ 会被解析为“引用”,这个“引用”可以是“左值”引用,也可以是“右值”引用。

例如:

template <typename T>
void func(T &&a) {
	std::cout << "a = " << a << std::endl;
}

int a = 123;
func(a);     // 被解析为左值引用
func(123);   // 被解析为右值引用

我们查看一下编译器是如何分析类型的:

执行:

nm -C ./a.out

可以得到如下结果:

1
这里说一下:
func(a) 对应的是 void func<int &>(int &)
func(123) 对应的是 void func<int>(int &&)

可以发现:
左值 a 被解析为 int &
右值 123 被解析为 int &&

因此,可以发现:

在模板函数(参数为双&&)中,所有模板参数都会被转换为引用

这不禁让人产生疑惑,我的模板参数明确填写了为双 & 为什么还能被转换为 单 ‘&’ 呢?

引用折叠

在C++的模板中具有一条潜规则:引用折叠。

引用折叠的意思大概就是:奇数的 & 被看作左值引用,偶数个 & 被看作右值引用。

当你想向模板函数中传入引用时,不管是左值引用还是右值引用,你都需要去写作 && 类型。

因为编译器是这样理解你的模板类型的:

首先,写成 && 会让编译器认为你这里是传入一个 引用 接下来,接下来,不管是左值还是右值,编译器都会将其解析为引用的状态:

例如:

int a = 123; // 左值,被解析为 int &
123; 				// 右值,被解析为 int &&

被解析之后的类型会被完全替换到模板参数中,例如:

template <typename T>
void func(T &&a) {...}

中的 T 会被完全替换:

void func(int & &&a) {...} // int a = 123;
void func (int && &&a) {...} // 123;

因此,可以发现 & 产生了很多个,而编译器就需要根据

奇数的 & 被看作左值引用,偶数个 & 被看作右值引用

这条原则来进行判断是左值引用还是右值引用。

remove_reference 的原理

remove_reference 是一个工具类,用于将引用类型提取出来(也就是去掉引用),例如:

template <typename T>
 void func(T &&a) {
		typename std::remove_reference<T>::type c;
		...
}

int main() {
		int n = 123;
		func(n);           // 这会在函数内部生成一个类型为int类型的变量c
		func(123);         // 这也会在函数内部生产一个类型为int类型的变量c
}

这东西的原理是什么呢?实际上利用了模板的特化:

template <typename T>        // 非特化
struct remove_reference {
		using type = T;
};

template <typename T>         // 特化一
struct remove_reference<T &> {
		using type = T;
};

template <typename T>         // 特化二
struct remove_reference<T &&> {
		using type = T;
};

是不是很简单?

通过第一个特化版本就可以将左值引用的类型提取出来,通过第二个特化版本就可以将右值引用的类型提取出来。

相关推荐

  1. C++迈向精通,学习笔记:类对象

    2024-07-16 23:44:03       31 阅读
  2. C++迈向精通:STLDeque复现

    2024-07-16 23:44:03       29 阅读
  3. C++引用指针介绍

    2024-07-16 23:44:03       24 阅读
  4. C++ 引用

    2024-07-16 23:44:03       59 阅读
  5. c++引用(&)

    2024-07-16 23:44:03       55 阅读
  6. C++引用

    2024-07-16 23:44:03       47 阅读
  7. C++引用

    2024-07-16 23:44:03       42 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-16 23:44:03       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-16 23:44:03       72 阅读
  3. 在Django里面运行非项目文件

    2024-07-16 23:44:03       58 阅读
  4. Python语言-面向对象

    2024-07-16 23:44:03       69 阅读

热门阅读

  1. 开放开源开先河(一)

    2024-07-16 23:44:03       20 阅读
  2. 动态规划算法专题四--两个数组dp问题

    2024-07-16 23:44:03       19 阅读
  3. 如何检查对象中键是否存在?

    2024-07-16 23:44:03       22 阅读
  4. 【嵌入式】面试笔试问题整理 (持续更新)

    2024-07-16 23:44:03       22 阅读
  5. 微信小程序-组件通信

    2024-07-16 23:44:03       19 阅读
  6. 【C语言实现双向循环链表】

    2024-07-16 23:44:03       22 阅读
  7. 前端面试题日常练-day88 【面试题】

    2024-07-16 23:44:03       18 阅读
  8. flex主轴元素控制优先级

    2024-07-16 23:44:03       18 阅读