``````template<typename T>
void f(ParamType param);

......
f(expr); // call f with some expression
``````

``````template<typename T>
void f(const T& param);      // ParamType is const T&
``````
``````int x = 0;
f(x);      // call f with an int
``````

• `ParamType`是一个指针或者引用，但不是`universal reference`(或者叫`forwarding references`).
• `ParamType`是一个`universal reference`
• `ParamType`既不是指针也不是引用。

## Case 1 : ParamType是一个指针或者引用，但不是universal reference

• 如果`expr`是一个引用，忽略其引用部分。
• 比较`expr``ParamType`的类型来决定`T`的类型。

### T&

``````template<typename T>
void f(T& param);       // param is a reference

......
int x = 27;                  // x is an int
const int cx = x;       // cx is a const int
const int& rx = x;     // rx is a reference to x as a const int

// call f
f(x);            // T is int, param's type is int&
f(cx);          // T is const int,  param's type is const int&
f(rx);         // T is const int,  param's type is const int&
``````

``````void f(int &x){

}

...
const int x  = 10;
f(x);       // error
``````

### const T&

``````template<typename T>
void f(const T& param);        // param is now a ref-to-const

......
int x = 27;                // as before
const int cx = x;     // as before
const int& rx = x;    // as before

......
f(x);         // T is int, param's type is const int&
f(cx);     // T is int, param's type is const int&
f(rx);      // T is int, param's type is const int&
``````

### T*

``````template<typename T>
void f(T* param); // param is now a pointer

......
int x = 27;
const int *px = &x;

f(&x);               // T is int, param's type is int*
f(px);              // T is const int, param's type is const int*
``````

## Case 2 : ParamType是Universal Reference

• 如果`expr`是左值，那么`T``ParamType`会被推断为左值引用。
• 如果`expr`是右值，那么就是Case 1的情况。
``````template<typename T>
void f(T&& param);       // param is now a universal reference

......
int x = 27;
const int cx = x;
const int& rx = x;
``````

``````f(x);          // x is lvalue, so T is int&, param's type is also int&
f(cx);         // cx is lvalue, so T is const int&, param's type is also const int&
f(rx);        // rx is lvalue, so T is const int&, param's type is also const int&
f(27);        // 27 is rvalue, so T is int, param's type is therefore int&&
``````

### 注意区别Universal Reference与右值引用

``````template<typename T>
void f(T&& param);           // universal reference

template<typename T>
void f(std::vector<T>&& param);       // rvalue reference
``````

## Case 3 : ParamType既不是指针也不是引用

``````template<typename T>
void f(T param); // param is now passed by value
``````

• 如果`expr`是引用类型，忽略。
• 如果`expr`带有const、volatile，忽略。
``````int x = 27;
const int cx = x;
const int& rx = x;
f(x);         // T's and param's types are both int
f(cx);      // T's and param's types are again both int
f(rx);      // T's and param's types are still both int
``````

``````void f(int x){

}

int main() {
const int x  = 10;

f(x);
}
``````

``````template<typename T>
void f(T param);

......
const char* const ptr = "Fun with pointers";       // ptr is const pointer to const object
f(ptr);             // pass arg of type const char * const
``````

## 数组作为参数

``````const char name[] = "J. P. Briggs";     // name's type is const char[13]
const char * ptrToName = name;       // array decays to pointer
``````

``````void myFunc(int param[]);
void myFunc1(int* param);         // same function as above
``````

### ParamType按值传递

``````template<typename T>
void f(T param); // template with by-value parameter

......
const char name[] = "J. P. Briggs";     // name's type is  const char[13]

f(name);           // name is array, but T deduced as const char*
``````

### ParamType为引用类型

``````template<typename T>
void f(T& param);

......
const char name[] = "J. P. Briggs";     // name's type is  const char[13]
f(name);             // pass array to f
``````

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

......
int keyVals[] = { 1, 3, 7, 9, 11, 22, 35 };
std::array<int, arraySize(keyVals)> mappedVals;
``````

## 函数作为参数

``````void someFunc(int, double);        // someFunc is a function;type is void(int, double)
template <typename T> void f1(T param);     // in f1, param passed by value
template <typename T> void f2(T &param);    // in f2, param passed by ref
f1(someFunc);        // param deduced as ptr-to-func; type is void (*)(int, double)
f2(someFunc);      // param deduced as ref-to-func; type is void (&)(int, double)
``````

(完)

## c++11-17 模板核心知识（五）—— 理解模板参数推导规则的更多相关文章

1. C++98/11/17表达式类别

目标 以下代码能否编译通过,能否按照期望运行?(点击展开) #include <utility> #include <type_traits> namespace cpp98 ...

2. Django（十五）模板详解：模板标签、过滤器、模板注释、模板继承、html转义

一.模板的基础配置及使用 [参考]https://docs.djangoproject.com/zh-hans/3.0/topics/templates/ 作为Web框架,Django提供了模板,用于 ...

3. Django模板-在视图中使用模板

之前我们已经有了自己的视图mysite.views.py中,应该是这样子的 from django.http import HttpResponse import datetime def curre ...

4. freeMarker（五）——模板开发指南补充知识

学习笔记,选自freeMarker中文文档,译自 Email: ddekany at users.sourceforge.net 模板开发指南补充知识 1. 自定义指令 自定义指令可以使用 macro ...

5. 14 张思维导图构建 Python 核心知识体系

ZOE是一名医学生,在自己博客分享了很多高质量的思维导图.本文中所列的 14 张思维导图(高清图见文末),是 17 年作者开始学习 Python 时所记录的,希望对大家有所帮助.原文:https:// ...

6. HTML中DOM核心知识有哪些（带实例超详解）

HTML中DOM核心知识有哪些(带实例超详解) 一.总结: 1.先取html元素,然后再对他进行操作,取的话可以getElementById等 2.操作的话,可以是innerHtml,value等等 ...

7. 零基础的学习者应该怎么开始学习呢？Python核心知识学习思维分享

近几年,Python一路高歌猛进,成为最受欢迎的编程语言之一,受到无数编程工作者的青睐. 据悉,Python已经入驻部分小学生教材,可以预见学习Python将成为一项提高自身职业竞争力的必修课.那么零 ...

8. 《Ext JS模板与组件基本知识框架图----模板》

最近在整理Ext JS的模板和组件,在参考<Ext JS权威指南>,<Ext JS Web应用程序开发指南>,<Ext JS API>等相关书籍后才写下这篇< ...

9. C++11 图说VS2013下的引用叠加规则和模板参数类型推导规则

背景:    最近在学习C++STL,出于偶然,在C++Reference上看到了vector下的emplace_back函数,不想由此引发了一系列的“探索”,于是就有了现在这篇博文. 前言:     ...

10. ASP.NET自定义控件组件开发 第五章 模板控件开发

原文:ASP.NET自定义控件组件开发 第五章 模板控件开发 第五章 模板控件开发 系列文章链接: ASP.NET自定义控件组件开发 第一章 待续 ASP.NET自定义控件组件开发 第一章 第二篇 接 ...

## 随机推荐

1. gif显示

public void gifplay(string path,ref Panel panel) { try{ Bitmap animatedGif = new Bitmap(path ); Grap ...

2. phpcmsv9全站搜索,不限模型

简单修改一下v9默认的搜索功能,可以不按模型搜索全站内容 下面是被修改后的search模块中的index.php文件 <?php defined('IN_PHPCMS') or exit('No ...

3. C#基于UDP实现的P2P语音聊天工具(1)

这篇文章主要是一个应用,使用udp传送语音和文本等信息.在这个系统中没有服务端和客户端,相互通讯都是直接相互联系的.能够很好的实现效果. 语音获取 要想发送语音信息,首先得获取语音,这里有几种方法,一 ...

4. ubuntu12.04 安装 opencv 2.4.8（非源代码编译）

一:安装所须要的各种库,如GTK3.xx 安装GCC:sudo apt-get install build-essential 安装CMakesudo apt-get install cmake su ...

5. windows安装weblogic和域的建立

6. odoo 权限问题

odoo 权限问题 权限组问题 权限组是为了将人员按组划分同一分配权限.权限组的建立是基于每个应用来实现的 建立一个应用的分组(可省略,主要用于创建用户时有选择项) 建立一条record记录model ...

7. docker--命令详解

查看版本: docker --version 查看docker信息: docker info 进入容器: docker exec -it bb /bin/bash #在容器中执行一个bash可以操作容 ...

8. [leetcode]Recover Binary Search Tree @ Python

原题地址:https://oj.leetcode.com/problems/recover-binary-search-tree/ 题意: Two elements of a binary searc ...

9. Android DrawLayout + ListView 的使用（一）

想做一个APP,设计中有侧边栏这个功能,所以现在开始学习下侧边栏的实现. 在官方的UI空间中已经给出了DrawerLayout这个侧滑的菜单空间. 因为在使用DrawerLayout的时候遇到了些问题 ...

10. 转载乙醇大师的appium简明教程

appium简明教程(11)——使用resource id定位(仅支持安卓4.3以上系统) 乙醇 2014-06-28 21:01 阅读:16406 评论:21 appium简明教程(10)——控件定 ...