Effective Modern C++

条款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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值