条款1:理解模板推导类型
template<class T>
void f(paramType param);
有三种情况:
- paramType是指针或引用类型,但不是万能引用。
- paramType是万能引用
- paramTypea既不是指针也不是引用
template<class T>
void f(T& param);
int x=27;
int const cx=x;
int const& rx=x;
f(x);//T,int. param,int&
f(cx);//T,int const.param,int const&.
f(rx);//T,int const.param,int const&.
template<class T>
void f(T const& param);
int x=27;
int const cx=x;
int const& rx=x;
f(x);//T,int. param,int const&
f(cx);//T,int.param,int const&.
f(rx);//T,int.param,int const&.
template<class T>
void f(T* param);
int x=27;
int const* px=&x;
f(&x);//T,int.param,int*
f(px);//T,int const.param,int const&;
万能引用
template<class T>
void f(T&& param);
int const cx=x;
int const& rx=x;
f(x);//T,int&. param,int&
f(cx);//T,int const&.param,int const&
f(rx);//T,int const&.param,int const&
f(27);//T,int.param,int&&
template<class T>
void f(T param);
int x=27;
int const cx=x;
int const& rx=x;
f(x);//T,int. param,int
f(cx);//T,int.param,int.
f(rx);//T,int.param,int.
条款2:理解auto类型推导
auto x=27;//int
auto const cx=x;//int const
auto const& rx=x;//int const&
万能引用
auto&& uref1=x;//lvalue, int&
auto&& uref2=cx;//lvalue,int const&
auto&& uref3=27;//rvalue, int&&
char const name[]="lijiaxin";//name type is char const[13]
auto arr1=name;//arr1 is char const*
auto& arr2=name;//arr2 is char const(&)[13]
void someFunc(int,double);//someFunc is void(int,double);
auto func1=someFunc; func1 is void(*)(int,double);
auto& func2=someFunc; func2 is void(&)(int,double);
请注意
auto x1=27;//x1 is int
auto x2{27};//x2 is int
auto x3={27};//x3 is initializer_list<int>
条款3:理解decltype
int const i=0;
//decltype(i) is int const;
bool f(Widget const& w);
//decltype(w) is Widget const&
//decltype(f) is bool(Widget const& w)
Wiget w;
//decltype(w) is Widget
template<class Container,class Index>
auto f(Container& c,Index i){
return c[i];//将在此处做类型推导
}
std::deque<int> d;
f(d,5)=10;//编译出错,f(d,5)返回d[5]的值而非引用.
函数返回值仅用auto占位,将丢掉const和&,因此将返回一个c[i]的拷贝的右值引用,而非c[i]的左值引用.如果想要返回c[i]的引用,应该按照如下方式修改:
template<class Container,class Index>
dycltype(auto) f(Container& c,Index i){
return c[i];
}
此处的auto没有在做类型推导,而是相当于把c[i]放置在auto所在的位置,由dycltype()做类型推导.因此,函数f的返回类型将是一个左值引用.
template<class Container,class Index>
dycltype(auto) f(Container& c,Index i){
return c[i];
}
std::deque<std::string> makeStringDeque();//某个工厂函数.
auto s=f(makeStringDeque(),5);//试图把deque的第5个元素保存至s.编译器报错.
函数f的参数需要一个Container的左值引用,然而makeStringDeque()却提供了一个右值.为了解决这个问题,可以给函数f一个重载版本.
template<class Container,class Index>
dycltype(auto) f(Container&& c,Index i){//此处接受一个右值
return c[i];
}
更好的方法是使用万能引用和完美转发.
template<class Container,class Index>
dycltype(auto) f(Container&& c,Index i){//此处接受一个右值
return std::forward<Container>(c)[i];
}
注意:
- decltype应用于不带括号的表达式,结果类型是该表达式的类型.
- decltype应用于带括号的左值表达式,结果类型是一个引用.
int x=10;
decltype((x)) y=x;//decltype((x)) is int&.
decltype(x) z=x;//decltype(z) is int.
条款4:查看类型推导结果的方法
- 鼠标悬浮在变量上面,IDE给出推导结果
- 利用IDE的错误信息查看编译器类型推导的结果
- 使用
typeid(object).name()
在运行时查看类型. - 使用
boost::typeindex::type_id_with_cvr
. - 使用(C++ Insights (cppinsights.io))网站.网站会把C++代码翻译为模板类型推导后的C++代码.
#include <cstdio>
int main()
{
const char arr[10]{2,4,6,8};
for(const char& c : arr)
{
printf("c=%c\n", c);
}
}
#include <cstdio>
int main()
{
const char arr[10] = {2, 4, 6, 8, '\0', '\0', '\0', '\0', '\0', '\0'};
{
const char (&__range1)[10] = arr;
const char * __begin1 = __range1;
const char * __end1 = __range1 + 10L;
for(; __begin1 != __end1; ++__begin1) {
const char & c = *__begin1;
printf("c=%c\n", static_cast<int>(c));
}
}
return 0;
}