更多精彩文章,欢迎关注作者微信公众号:码工笔记
一、类型推导
Item 1: 模板类型推导
Case 1: 形参是引用或指针类型,但不是 Universal Reference
- 形参为引用
template<typename T>
void f(T& param);
int x = 27;
const int cx = x;
const int& rx = x;
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&
- 形参为 const 引用
template<typename T>
void f(const T& param); //param 指定了const,后续在类型推导时不需要将实参的const推导到T中
int x = 27;
const int cx = x;
const int& rx = x;
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&
- 形参为指针
template<typename T>
void f(T *param);
int x = 27;
const int *px = &x;
f(x); //T is int, param类型为int*
f(px); //T is const int; param类型为const int*
注:形参为 const 指针的情况参考形参为 const 引用时,即T推导为int,params类型为const int*;
Case 2:形参为 Universal Reference
这里按实参类型分为两种情况:
- 实参为 lvalue,则T和paramType都推导为lvalue reference。
- 实参为 rvalue,参考 Case 1
template<typename T>
void f(T&& param);
int x = 27;
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&
f(27); //T为int, param类型为int&& 【注意】
Case 3:形参既不是指针也不是引用(包括Universal Reference)
值传递:
- 如果实参为引用类型,则只关注其类型而忽略其是一个引用
- 忽略实参的 const 和 volatile 属性
template<typename T>
void f(T param);
int x = 27;
const int cx = x;
const int& rx = x;
f(x); //T为int,param类型为int
f(cx); //T为int,param类型为int
f(rx); //T为int,param类型为int
template<typename T>
void f(T param);
const char *const ptr = "Fun with poiters";
f(ptr); //T和param都是const char* (描述ptr变量本身的后一个const被忽略了)
另外,实参为数组或函数名的情况下,如果形参不是引用类型,则其类型会被推导为指针。
Item 2:auto 类型推导
逻辑基本与模板类型推导相同,注意以下两点:
- auto的类型推导会将大括号初始化表达式推导为std::initializer_list,而模板类型推导不会
- auto x = {xx, yy, ...}
- auto作为函数返回值类型或lambda表达式参数类型时,表示使用模板推导而不是auto类型推导
auto createInitList() { return {1,2,3}; //error: can't deduce type for {1,2,3} } std::vector<int> v; ... auto resetV = [&v](const auto& newValue) { v = newValue; } //c++ 14 ... resetV({1,2,3}); //error: can't deduce type for {1,2,3}
Item 3:decltype 类型推导
给定一个变量名或表达式,输出其类型。注意:
- 如果给定的是左值表达式(类型为T)而非变量名,decltype返回 T&
- c++14支持decltype(auto),它由其初始化值来做类型推导,使用的是decltype的规则
示例:返回数据为容器元素,其类型取决于Container,返回值类型使用decltype
//c++14
template<typename Container, typename Index>
decltype(auto) authAndAccess(Container&& c, Index, i)
{
authenticateUser();
return std::forward<Container>(c)[i];
}
//c++11
template<typename Container, typename Index>
auto authAndAccess(Container &&c, Index i) -> decltype(std::forward<Container>(c)[i])
{
authenticateUser();
return std::forward<Container>(c)[i];
}
二、auto的使用
- auto类型的变量必须被初始化,可以减少类型不匹配的问题,降低重构开销,减少typing
- auto类型可能会由于"Invisible" proxy type而出现推导错误的情况
- 可使用显式类型的初始化值来确保 auto 能正确推导出目标类型,并且能向读者传达正确的信息
例1:
double calcEpsilon(); //返回值类型为double
//显式指定强转为float类型,显式cast可向读者传递此处的确就是要降低精度
auto ep = static_cast<float>(calcEpsilon());