第十六章:模板与泛型编程2

1.模板实参推断

1.1 自动类型转换

const转换: 非const对象的引用(指针)传递给一个const的引用(指针)形参。
数组或函数指针转换: 若函数实参不是引用类型,则可以对数组或函数类型的实参应用正常的指针转换。

1.2 函数模板显示实参
template <typename T1, typename T2, typename T3>
T1 sum(T2,T3);            //T2,T3可以通过调用实参推断,T1无法推断,需要显示指定

sum<long long>(23, 23.5);  //显示指定返回类型T1的类型 long long sum(int, double);
1.3 尾置返回类型

原:
  当我们不知道返回结果的准确类型,但知道是所处理序列的元素类型。
解:

template <typename It>
auto fcn1(It beg, It end)->decltype(*beg)
{
	return *beg;         //返回引用
}

template <typename It>
auto fcn2(It beg, It end)->typename remove_reference<decltype(*beg)>::type
{
	return *beg;         //返回序列中一个元素的拷贝
}
1.4 函数指针和实参推断(使指针指向一个模板实例)
template <typename T>
int compare(const T&, const T&){/*...*/}

int (*pf)(const int&, const int&) = compare;  //指向compare的int实例版本

当参数是一个函数模板实例的地址时,程序上下文必须满足:对每个模板参数,能唯一确定其类型或值。

void fcn(int(*)(const string&, const string&));
void fcn(int(*)(const int&, const int&));

fcn(compare);         //歧义
fcn(compare<int>);    //显示指定

2.模板实参推断和引用

2.1 模板实参推断:
/*函数参数为左值引用*/
template <typename T> void f1(T&);       //可以传入i(int),ci(const int),右值不可以
template <typename T> void f2(const T&); //三者均可,T都为int

/*函数参数为右值引用*/
template <typename T> void f3(T&&);      //传入i(int&),ci(const int&),右值(int)
2.2 引用折叠
T& &|T& &&|T&& &————>T&
T&& && ---->T&&

若函数实参是指向模板参数的右值引用(T&&),则可传递给它任意类型的实参。
左值=》T&:函数参数通过引用折叠被实例化为(int& &&=》int&

/*std::move*/
template <typename T>
typename remove_reference<T>::type&& move(T&&t)
{
	return static_cast<typename remove_reference<T>::type&&>(t);
}

template<class T> struct remove_reference      {typedef T type;};
template<class T> struct remove_reference<T&>  {typedef T type;};
template<class T> struct remove_reference<T&&> {typedef T type;};
2.3转发

参数通过一个函数转发给另一函数发生调用。

template <typename F, typename T1, typename T2>
void flip1(F f,T1 t1,T2 t2)
{
	f(t1,t2);          //调用另一个函数
}

void f(int &v1, int v2){/*改变v1*/}

问题:
  当调用flip1(f , j , 42)时,j的值并没有被改变,改变的只是临时的t1。
改进版:

template <typename F,typename T1,typename T2>
void flip2(F f, T1 &&t1, T2 &&t2)
{
	f(t1, t2);          //调用另一个函数
}

void g(int &v1, int &&v2){/*...*/}

此时调用flip1(f , j , 42),j的值会发生改变,但t2变成了左值(函数参数变量均为左值),无法传给右值引用。
最终版:

template <typename F,typename T1,typename T2>
void flip3(F f,T1 &&t1,T2 &&t2)
{
	f(std::forward<T1>(t1), std::forward<T2>(t2));          //调用另一个函数
}
//std::forward<T> 返回T&&

j --> (int&) t1 --> T1(int&) --> std::forward< T1 > --> int&
42 --> t2(int) --> T2(int) --> std::forward< T2 > --> int&&

2.4 重载与模板
  • 当多个重载模板对一个调用提供同样好的匹配时,应选择最特例化的版本。
  • 对于一个调用,如果一个非函数模板与一个函数模板提供同样好的匹配,则选择非模板版本。
2.5 可变参数模板

参数包:可变数目的参数(≥0),用""表示一个模板参数为一个包。
sizeof…(参数名): 返回包中有多少元素。

template<typename T, typename...Args>        //Args为模板参数包
void fcn(const T&, const Args&...rest);      //args为函数参数包

sizeof...(Args) == sizeof...(rest);
fcn(str, 42, "hi") ==> fcn(const string&, const int&, const char[3]&);

包扩展

  • rest…: 生成实参列表
  • fcn(rest)…: 对rest包中的每个元素进行fcn调用(fcn(r1),fcn(r2)…)
  • std::forward< Args >(args)…: 对每个元素进行转发,扩展为std::forward< T1 >(t1),std::forward< T2 >(t2)…
/*make_share<T>(...)*/
template <typename T,typename...Args>
shared_ptr<T> make_share(Args&&...args)
{
	return shared_ptr<T>(new T(std::forward<Args>(args)...));
}
2.6模板特例化

通用模板的定义对特定类型不合适,如无法对指针进行比较,本质是实例化一个模板。

2.6.1 函数模板特例化
template <>                        //<>表明我们将为所有模板参数提供实参
int compare(const char* const&p1, const char* const&p2)
{/*...*/}
2.6.2 类模板特例化
template <>
class A<int>                      //显示指定特例化类型
{
	/*....*/
};
2.6.3 类模板部分特例化
template<class T>
struct remove_reference{typedef T type;}             //普通
template<class T>
struct remove_reference<T&>{typedef T type;}         //左值
template<class T>
struct remove_reference<T&&>{typedef T type;}        //右值

remove_reference<decltype(42)>::type                 //int-->int
remove_reference<decltype(i)>::type                  //int&-->int
remove_reference<decltype(std::move(i))>::type       //int&&-->int
2.6.4 类模板成员特例化
template <typename T>
struct Foo
{
	void bar(){/*...*/}
};
template<>
void Foo<int>::bar(){/*...*/}     //当T为int时,调用特例化的bar
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值