001-EMC 深入解读-理解模板型别推导
Posted --Allen--
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了001-EMC 深入解读-理解模板型别推导相关的知识,希望对你有一定的参考价值。
EMC 第一章条款一,一上来就出个王炸——有关于函数模板的推导规则。
1. 问题
似乎你在使用的时候并未关注过这些事情,因为一切看起来相当自然,你也用的很爽。比如:
template <typename T>
T add(T a, T b)
return a + b;
这是一个计算两数之和的函数,你可以传递 float, double, int 等支持 operator+ 类型的参数,而不用为每一种类型都写一份 add 函数。
但是,上面的函数模板你也可以写成:
template <typename T>
T add(T& a, T& b)
return a + b;
template <typename T>
T add(const T& a, const T& b)
return a + b;
template <typename T>
T add(T&& a, T&& b)
return a + b;
然而,上面这 3 种写法在 C++11 中都好使。到底哪种比较好?或者说,有什么区别?从直觉上来说,写在 add(T a, T b) 是值传递,而带 & 的则是引用传递,带 const 则表示希望对象保持常量属性。你的直觉是对的。
那么 T&& 是什么?这是 C++11 出现的特有语法,你也许听说过右值引用,很抱歉,看起来 T&& 确实像右值引用,不过,当 && 出现在模板参数 T 后面时,则称为 Universal Reference(通用引用、万能引用)。接下来我们给一个比较正式的定义:
函数模板中持有型别形参 T 时,Universal Reference 写作 T&&
现在将问题抽象一下,对于下面的模板:
template<typename T>
void f(ParamType param)
问题:在不同的模板参数里,传递不同类型的参数,T 会被编译器推导为什么?ParamType 又是什么?
例如:
template<typename T>
void f(const T& param) // ParamType = const T&
int x = 27;
const int cx = x;
const int& rx = x;
当你调用 f(x)
, f(cx)
, f(rx)
时,T 是什么,ParamType 是什么?
事实上,上面的 3 种情况,T 全部被推导为 int
,所以,ParamType = const T&
= const int&
.
如果模板是:void f(T& param)
,情况又是怎样呢?如何在你的编译器中验证?
2. 实验
我们没一个比较好的直接的方法在程序里打印出推导的类型,但是可以利用链接器的错误提示来看到实际推导类型。
2.1 void f(T& param)
编译以下代码,命名为 deduce01.cpp
- 推导 f(x)
// deduce01.cpp
template <typename T>
void f(T& param); // 故意不写 f 的定义
int main()
int x = 27;
const int cx = x;
const int& rx = x;
f(x);
// f(cx);
// f(rx);
return 0;
使用下面方式编译:
$ g++ -std=c++11 deduce01.cpp
图1 调用 f(x)
可以看到,f(x) 里,T 被推导为 int,而 ParamType 被推导为 int &.
- 推导 f(cx)
如果调用 f(cx),再进行编译:
// deduce.01.cpp
template <typename T>
void f(T& param); // 故意不写 f 的定义
int main()
int x = 27;
const int cx = x;
const int& rx = x;
// f(x);
f(cx);
// f(rx);
return 0;
图2 调用 f(cx)
可以看到,调用 f(cx) 时,T 被推导为 int const, ParamType 被推导为 int const&.
- 推导 f(rx)
如果调用 f(rx),再进行编译:
// deduce.01.cpp
template <typename T>
void f(T& param); // 故意不写 f 的定义
int main()
int x = 27;
const int cx = x;
const int& rx = x;
// f(x);
// f(cx);
f(rx);
return 0;
图3 调用 f(rx)
推导的类型和调用 f(cx) 一模一样。
2.2 void f(const T& param)
同样的,我们编译 deduce02.cpp,使用上述方法编译:
// deduce02.cpp
template <typename T>
void f(const T& param); // 故意不写 f 的定义
int main()
int x = 27;
const int cx = x;
const int& rx = x;
// 这里一次调用 3 次 f
f(x);
f(cx);
f(rx);
return 0;
图4 调用 f(x), f(cx), f(rx)
你发现,只报了一个链接错误,这意味着这 3 次调用,推导的结果是一样的。T 被推导为 int,而 ParamType 被推导为 int const&.
3. 总结
- 掌握查看推导类型的方法
后文我们继续讨论具体的规则:
- ParamType 是引用或指针,但不是通用引用
- ParamType 是通用引用
- ParamType 既非指针也非引用
以上是关于001-EMC 深入解读-理解模板型别推导的主要内容,如果未能解决你的问题,请参考以下文章
支持向量机SVM原理解读,以及PyQt5融合SVM的代码实现,没有公式推导(已经很成熟,很难改公式,数学专业的可以推导学习)