条款一 了解模板类型推断

基本情况

首先定义函数模板和函数调用的形式如下,在编译期间,编译器推断T和ParamType的类型,两者基本不相同,因为ParamType常常包含const、引用等修饰符

template<typename T>
void f(ParamType param); // 函数模板形式
f(expr); // 函数调用

存在T的类型即为expr类型的情况,如下T为int

templat<typename T>
void f(const T& param);
int x = ;
f(x); // T -> int

但是T的类型的推断不仅与expr有关,还和ParamType有关。有如下三种情况:

  • ParamType是指针或引用类型,但不是通用引用(universal reference)

  如果expr是引用类型,则忽略引用部分

  然后通过模式匹配expr与ParamType来决定T

  向函数模板传递一个const对象是合法的,T会添加对应的const,如下所示

template<typename T>
void f(T& param); int x = ;
const int cx = x;
const int& rx = x; f(x); // T -> int, param -> int&
f(cx); // T -> const int, param -> const int&
f(rx); // T -> const int, param -> const int&

  以上示例演示的是左值引用形参,对于右值应用也一样,当然只有右值实参能传入右值引用形参,但对于类型推断没有影响

  const T&的情况

template<typename T>
void f(const T& param); int x = ;
const int cx = x;
const int& rx = x; f(x); // T -> int, param -> int&
f(cx); // T -> int, param -> const int&
f(rx); // T -> int, param -> const int&

  T*的情况

template<typename T>
void f(T* param); int x = ;
const int *px = &x; f(&x); // T int, param -> int*
f(px); // T const int, param -> const int*
  • ParamType是通用引用

  如果expr是左值,则T与ParamType被推断为左值引用。这非常不同寻常,首先这是模板类型的唯一情境T被推断为引用,然后即使ParamType的语法是一个右值引用,它推断出的类型也是左值引用

  如果expr是右值,则适用情况一的规则

template<typename T>
void f(T&& param); int x = ;
const int cx = x;
const int& rx = x; f(x); // x -> lvalue, T -> int&, param -> int&
f(cx); // x -> lvalue, T -> const int&, param -> const int&
f(rx); // x -> lvalue, T -> const int&, param -> const int&
f(); // 27 -> rvalue, T -> int, param -> int&&

  当使用通用引用的时候,左值实参与右值实参的类型推断不同,但是对于非通用引用则没有区别

  • ParamType既不是指针又不是引用

  如果expr是引用类型,则忽略引用部分

  在忽略引用部分后,如果expr是const或volatile,也同时忽略

template<typename T>
void f(T param); int x = ;
const int cx = x;
const int& rx = x; f(x); // T -> int, param -> T
f(cx); // T -> int, param -> T
f(rx); // T -> int, param -> T

  由于是拷贝,实参的const不再生效

  以下是一个特殊情形分析

template<typename T>
void f(T param); const char* const ptr = "Fun with pointers"; f(ptr); // T -> const char*, param -> const char*

  ptr是按值传递,则ptr的const需要舍弃,则param的类型为const char*

数组实参

尽管数组类型与指针类型在有时候可以转换(许多情境下数组退化为指向第一个元素的指针,array-to-pointer decay rule),但依旧值得探讨一些细节问题。

实际上没有数组类型的形参,其会转换为指针

一般数组情形

template<typename T>
void f(T param); const char name[] = "J. P. Briggs"; f(name); // T -> const char*, param -> const char*

引用数组情形

template<typename T>
void f(T& param); const char name[] = "J. P. Briggs"; f(name); // T -> const char[13], param -> const char(&)[13]

以下函数在编译器能直接获取已知数组的长度

template<typename T, std::size_t N>
constexpr std::size_t arraySize(T (&)[N]) noexcept {
return N;
}

函数实参

函数类型也会退化为函数指针类型,其规则和数组相同

void someFunc(int, double);

template<typename T>
void f1(T param); template<typename T>
void f2(T& param); f1(someFunc); // T -> void (*)(int, double), param -> void (*)(int, double)
f2(someFunc); // T -> ?, param -> void (&)(int, double)

总结

  • 在模板类型推断过程中,引用实参被当做非引用处理,所以他们的引用性被忽略
  • 当推断通用引用的形参时,左值实参特殊对待
  • 当推断传值形参的类型时,const、volatile的实参忽略其const、volatile
  • 在模板类型推断的过程中,数组或函数的实参退化为指针,除非他们被用来初始化引用

[Effective Modern C++] Item 1. Understand template type deduction - 了解模板类型推断的更多相关文章

  1. [Effective Modern C++] Item 2. Understand auto type deduction - 了解auto类型推断

    条款二 了解auto类型推断 基础知识 除了一处例外,auto的类型推断与template一样.存在一个直接的从template类型推断到auto类型推断的映射 三类情况下的推断如下所示: // ca ...

  2. [Effective Modern C++] Item 3. Understand decltype - 了解decltype

    条款三 了解decltype 基础知识 提供一个变量或者表达式,decltype会返回其类型,但是返回的内容会使人感到奇怪. 以下是一些简单的推断类型: ; // decltype(i) -> ...

  3. 现代C++之理解模板类型推断(template type deduction)

    理解模板类型推断(template type deduction) 我们往往不能理解一个复杂的系统是如何运作的,但是却知道这个系统能够做什么.C++的模板类型推断便是如此,把参数传递到模板函数往往能让 ...

  4. [Effective Modern C++] Item 6. Use the explicitly typed initializer idiom when auto deduces undesired types - 当推断意外类型时使用显式的类型初始化语句

    条款6 当推断意外类型时使用显式的类型初始化语句 基础知识 当使用std::vector<bool>的时候,类型推断会出现问题: std::vector<bool> featu ...

  5. [Effective Modern C++] Item 4. Know how to view deduced types - 知道如何看待推断出的类型

    条款四 知道如何看待推断出的类型 基础知识 有三种方式可以知道类型推断的结果: IDE编辑器 编译器诊断 运行时输出 使用typeid()以及std::type_info::name可以获取变量的类型 ...

  6. 《Effective Modern C++》翻译--条款2: 理解auto自己主动类型推导

    条款2: 理解auto自己主动类型推导 假设你已经读过条款1关于模板类型推导的内容,那么你差点儿已经知道了关于auto类型推导的所有. 至于为什么auto类型推导就是模板类型推导仅仅有一个地方感到好奇 ...

  7. [Effective Modern C++] Item 5. Prefer auto to explicit type declarations - 相对显式类型声明,更倾向使用auto

    条款5 相对显式类型声明,更倾向使用auto 基础知识 auto能大大方便变量的定义,可以表示仅由编译器知道的类型. template<typename It> void dwim(It ...

  8. Effective Modern C++ Item 27:重载universal references

    假设有一个接收universal references的模板函数foo,定义如下: template<typename T> void foo(T&& t) { cout ...

  9. [Effective Modern C++] Item 7. Distinguish between () and {} when creating objects - 辨别使用()与{}创建对象的差别

    条款7 辨别使用()与{}创建对象的差别 基础知识 目前已知有如下的初始化方式: ); ; }; }; // the same as above 在以“=”初始化的过程中没有调用赋值运算,如下例所示: ...

随机推荐

  1. 使用indent命令帮助排版源代码

    在写代码时候,特别是在vim中编辑代码时候,你可能会不太注意代码风格问题,比如‘{’符号放在行末还是下一行行首等等, 这样你把自己代码与别人的代码merge时候,就会出现代码风格不一的问题,这里就推荐 ...

  2. Qt通过odbc读取excel数据

    传统的读取方式是通过Excel.Application,这种方式不仅操作繁琐,而且速度也不快. 通过odbc读取,可以使用select语句直接读取整个工作表,处理excel数据就跟数据库一样方便. 当 ...

  3. TCP的状态

    在TCP层,有个FLAGS字段,这个字段有以下几个标识:SYN, FIN, ACK, PSH, RST, URG. 其中,对于我们日常的分析有用的就是前面的五个字段. 它们的含义是: SYN表示建立连 ...

  4. (原)Ubuntu14中安装GraphicsMagick

    转载请注明出处: http://www.cnblogs.com/darkknightzh/p/5661439.html 参考网址: http://comments.gmane.org/gmane.co ...

  5. Virtual Environments

    virtualenv 再另一篇随笔中已经提到过virtualenv.如果我们有好几个不同的项目,他们需要的第三方包版本不同,那怎么办呢.这时候就需要virtualenv创建一个虚拟环境,里面包含了一个 ...

  6. Tomcat学习笔记 - 错误日志 - Tomcat访问Manager apps出现401 Unauthorized错误

    原因是配置文件中未指定管理员身份. 打开tomcat>conf>tomcat-user.xml文件,添加如下代码: <role rolename="admin-gui&qu ...

  7. 宽带连接工具[bat]

    功能概述: 本工具使用批处理编写,提供自动判断网络状态以决定断开或是连上网络,本月已用宽带时长,到月初自动清零.提供联网日志功能,可以记录下所有的连接或断开网络记录.如果连接失败,自动提示输入密码,特 ...

  8. Nginx的Upload上传模块

    前段时间做一个项目,需要上传文件,差不多需要20M左右,普通用php处理会比较麻烦,经常超时,而且大量占用资源.于是搜索了下,决定用nginx的upload上传模块来处理. 你可以在这里:http:/ ...

  9. CSS3之背景色渐变

    在css2时代,页面背景色渐变,按钮背景渐变效果主要是通过图片实现,css3中可通过 gradient 实现背景色渐变,图片作为一种资源,每次在页面加载时都要从服务器下载,这样如果页面很大需要渐变的效 ...

  10. C# Exception类

    一.异常类 1.在C#中所有的异常都是使用一个异常类型的示例对象表示的,这些异常类型都是继承自System.Exception类型,或者直接使用System.Exception类型的实例对象: 2.在 ...