C++第十六章:模板实参推断--引用折叠--转发

首先能用于函数模板的转换:
与往常一样,顶层const 无论是在形参中还是在实参中,都会被忽略。在其他类型转换中,能在调用中应用于函数模板的包括如下两项。
能:
const转换 :可以将一个非const对象的引用(或指针)传递给一个const的
引用(或指针)形参
数组或函数指针转换 :如果函数形参不是引用类型,则可以对数组或函数类型的实参应用正常的指针转换。一个数组实参可以转换为一-个指向其首元素的指针。类似的,一个函数实参可以转换为一个该函数类型的指针(参见4.11.2节,第143页)。
不能
其他类型转换,如算术转换派生类向基类的转换以及用户定义的转换,都不能应用于函数模板。
在这里插入图片描述
函数模板参数

template <typename T>
int compare(const T &v1, const T &v2)
{
..................
}
long lng;
compare(lng,1024);//错误的调用,都是相同的T类型,
//但推断出来第一个是long第二个int,在函数模板中这种类型不能转换
//但可以显示指定也可以显示指定
compare<long>(lng,1024)//正确compare(long,long)


改一下 主体 int compare(const long &v1, const T &v2)
int x=20;
compare(x,1024);//正确,函数参数类型不是模板参数,则可以正常转换

函数模板参数返回类型:

template <typename T1,typename T2,typename T3>
T1 sum(T2,T3);//因为没有像函数调用实参一样来推断T1类型,所以要显示提供T1类型

auto va13 = sum<long long >(i,lng) //显示指定T1是long long 最右T2T3可以省略被推断出来


使用尾置类型可以
template <typename IT>
??? &fcn(IT beg , IT end)
{
......
return *beg;
}
不能确定返回类型
vector<int> vi{....}
Blob<string> ca{.....}
auto &i=fcn(vi.begin(),vi.end());返回类型int&
auto &i=fcn(ca.begin(),ca.end());返回类型string&

//采用尾置类型 自动判断
template <typename IT>
auto &fcn(IT beg , IT end) ->decltype(*beg)
{
......
return *beg;
}

引用折叠:注意: 引用折叠只能应用于间接创建的引用的引用,如类型别名或模板参数。



template <typename T>
void f1(T&);
f1(i);//i是int 所以模板参数类型T是int
f1(ci);//ci是const int 所以模板参数类型T是const int
f1(5);//错误:传递给一个&参数的实参必须是一个左值

template <typename T>
void f1(const T&);
//当函数参数本身是const时,T的类型推断结果不会是一个const类型。
//const已经是函数参数类型的一部分:因此,它不会是模板参数类型的一部分
f1(i);//i是int 所以模板参数类型T是int
f1(ci);//ci是const int 但模板参数T是int
f1(5);//一个const &参数可以绑定到一个右值;T是int


/
右值引用绑定一个右值正常
template <typename T>
void f3(T&&);
f3(42);//实参是一个int类型的右值;模板参数T是int

但通常不能将一个右值引用绑定到一个左值,但在模板类型中是例外,产生引用折叠
当将一个左值(如i)传递给函数的右值引用参数(如T&&),
编译器会推断模板类型参数为实参的左值引用类型
调用f3(i),会推断T的类型为int&而不是int(折叠的作用)
X& &, X& &&, X&& &,都折叠为X&
X&& &&折叠成X&&
f3(i);//实参是一个左值;模板参数T是int&   然后int& &&折叠为int&
f3(ci);//ci是const int 但模板参数T是const int&

这两个规则导致了两个重要结果:
1.如果一个函数参数是一个指向模板类型参数的右值引用,则它可以被绑定到一个左值。
2.如果实参是一个左值,则推断出的模板实参将是一个左值引用,且函数参数将被实例化为
一个左值引用参数。

结果:这两个规则暗示我们,我们可以将任意类型的实参传递给T&&类型的函数参数。
对于这种类型的参数,显示我们也可以传递给它右值,当然也可以传递左值。

转发:使用std::forward保存类型信息

template <typename F,typename T2,typename T3>
void flip2(F f,T1 &&t1,T2 &&t2)
{
    f(t2,t1);
}
void g(int &&i,int &j)
{
   .........
}
对于调用
flip2(g,i,42);
首先T1接收i推断为int& 则t1类型为int& &&又因为模板参数,所以t1类型折叠为int&
    T2接收42判断为int,则t2类型是int &&
    g中参数i是个右值引用,接收的t2虽然是一个右值引用,但他此时作为一个变量传递
    是一个左值,在g中都是普通函数参数所以不能把一个右值引用绑定到左值
解决办法:使用std::forward保存实参类型信息    

template <typename F,typename T2,typename T3>
void flip2(F f,T1 &&t1,T2 &&t2)
{
    f(std::forward<T2>(t2),std::forward<T1>(t1));//与std::move不同,要显示模板实参
}
此时再调用
flip2(g,i,42);//i将以int&传递给g中j,42将以int&& 传递给t1
              //所以g中i是int&&,j是int&,在g中i发生引用折叠int&& &&折叠为int&& 
              //其实就是在普通函数参数中采用std::forward结合模板实参
              //自己理解:使得普通函数参数能够产生引用折叠int&& &&折叠为int&& 
书上解释
f(std::forward<T2>(t2),std::forward<T1>(t1));
//这里的T2通过传递给flip2中T2的实参42判断为普通类型int,
//则std::forward<T2>返回int&&最后判断t2能够接收42,t2类型为int&&

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值