[Effective Modern C++] Item 1. Understand template type deduction - 了解模板类型推断

时间:2022-12-16 10:19:32

条款一 了解模板类型推断

基本情况

首先定义函数模板和函数调用的形式如下,在编译期间,编译器推断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. &lbrack;Effective Modern C&plus;&plus;&rsqb; Item 2&period; Understand auto type deduction - 了解auto类型推断

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

  2. &lbrack;Effective Modern C&plus;&plus;&rsqb; Item 3&period; Understand decltype - 了解decltype

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

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

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

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

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

  5. &lbrack;Effective Modern C&plus;&plus;&rsqb; Item 4&period; Know how to view deduced types - 知道如何看待推断出的类型

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

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

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

  7. &lbrack;Effective Modern C&plus;&plus;&rsqb; Item 5&period; Prefer auto to explicit type declarations - 相对显式类型声明,更倾向使用auto

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

  8. Effective Modern C&plus;&plus; Item 27:重载universal references

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

  9. &lbrack;Effective Modern C&plus;&plus;&rsqb; Item 7&period; Distinguish between &lpar;&rpar; and &lbrace;&rcub; when creating objects - 辨别使用&lpar;&rpar;与&lbrace;&rcub;创建对象的差别

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

随机推荐

  1. MSDN for VS2012 的安装

    在VS2012中,由于MSDN默认不内置,VS2008 以上的就没有独立的 MSDN 了 ,而是被 Microsoft Help Viewer 取代了. 该组件包含在 VS2012 的 ISO 安装镜 ...

  2. Linux 学习手记&lpar;5&rpar;:使用Vim文本编辑器

    Vim是从vi发展而来的文本编辑器.vi是Linux及类Unix系统中主流的命令行文本编辑器,Vim 除了对vi功能上进行了加强,还加入了对GUI的支持.绝大多数的Linux系统上均安装了vim,vi ...

  3. 帝国CMS 6&period;0功能解密之新版结合项功能,帝国结合项使用

    可以用来做A-Z信息检索    某字段等于多少,输出  等等 帝国CMS6.0在继承以往版本结合项功能的基础上又新增很多特性,更强大.今天我们就专门来讲解6.0的结合项改进. 回顾下以往版本的结合项语 ...

  4. &lbrack;CSS&rsqb;学习总结

    1. 遮挡层 .occlusion { opacity: -.35;/*透明程度*/ -moz-opacity: -.35; filter: alpha(opacity=-35); height: 1 ...

  5. 超简单fedora20&lpar;linux&rpar;下JDK1&period;8的安装

    (博客园-番茄酱原创) 去官网下载linux版本的jdk,如果你的fedora是64位,就选择64位的jdk,jdk-8u20-linux-x64.tar.gz. 将下载好的jdk解压到当前目录下,解 ...

  6. java中public等权限问题和final的使用

    1.public:public表明该数据成员.成员函数是对所有用户开放的,所有用户都可以直接进行调用 2.private:private表示私有,私有的意思就是除了class自己之外,任何人都不可以直 ...

  7. JavaScript decodeURI&lpar;&rpar; 和 encodeURI&lpar;&rpar; 函数

    定义和用法 decodeURI() 函数可对 encodeURI() 函数编码过的 URI 进行解码. 语法 decodeURI(URIstring) 参数 描述 URIstring 必需.一个字符串 ...

  8. android反编译工具 ApkDec-Release-0&period;1

    (1 )使用帮助    1. 选择 all  全部编译内容包括jar .xml .及其他资源文件    2. 选择 jar  只反编译并打成jar 包    3. 反编译后你可以使用jd-gui.ex ...

  9. RecyclerView 加点击事件

    在apapter里去实现. View.OnClickListener onClickListener = new View.OnClickListener() { @Override public v ...

  10. Python知识点整理,基础2 - 列表操作