美文网首页C++
c++语法系列之7-- 函数模板

c++语法系列之7-- 函数模板

作者: hello12qwerz | 来源:发表于2018-04-01 09:50 被阅读0次
水滴石穿,木锯绳断。
-- 诸君共勉

(C++ Templates笔记)

1 函数模版的定义

template <typename T>
inline T const& max(T const& a, T const& b) {
  return a < b ? b: a;

说明:
1)typename后面的T为模板参数,max后面的参数为调用参数;
2)也可以使用class代替typename,但是class可能具有误导性,表明必须为一个类,而实际上模板参数也可以为基本类型。所以推荐全部使用typename;
3)不能用struct代替typename;
4)函数模板编译的时候,会被编译两次:
(1)模板实例化之前,检查模板码本身是否有语法错误;
(2)实例化期间检查所有的调用是否有效; => 这个步骤导致函数模板的编译和普通函数的编译会有差异。普通函数只要有该函数的声明(也即不需要定义 )就可以编译通过。函数模板会查看模板的定义。所有本文开头函数模板的定义中使用最简单的情况:使用内联函数,以便在头文件中声明的时候并定义。
5)实参演绎:编译器根据调用参数的实参推断出模板参数的过程;
6)函数模板的调用参数在实参演绎的时候不允许进行自动类型转换;

max(4,7);//OK,实参为int
max(4,4.2);//Error:没有对应的函数

可以有三种方法解决上面这个编译错误:
(1)对实参进行显示的强制类型转换:

max(static_cast<double>(4) , 4.2);//ok

(2)显示指定模板参数的类型:

max<double>(4 , 4.2);//ok

(3)指定两个可以具有不同类型的模板参数

2 关于返回值

考虑下面的代码:

template <typename T1, typename T2>
inline T1 max(T1 const& a, T2 const& b) {
    return a < b ? b: a;
}

我们可能会想通过上面的方式来任意比较两个类型的值得大小。以上例子隐含有以下几点问题:
1)T1, T2需要支持两个类型之间的operator< 操作符;
2)返回值需要转换为T1,如果T2对应的变量值大于T1,此时会将T2强制转换为T1;
3)T2转换为T1的时候,会创建一个新的临时局部变量。这会导致不能使用引用返回结果。这也是为什么上面的返回类型为T1 而不是T1 const&。
另外:
调用函数模板的时候,必须指定不能被隐式演绎的模板实参之前的所有实参类型
比如:

template <typename RT,  typename T1, typename T2>
inline RT max(T1 const& t1, T2 const& t2) {
....
}

max<double>(1 , 4.2);//等价于max<double,int,double>(1 , 4.2);

2 重载函数模板

函数模板可以被重载,可以同时存在普通同名函数和函数模板。
这里有几个规则:
1)对于非模板函数和模板函数,在条件相同情况下,重载解析过程会调用非模板函数;
2)如果函数模板可以产生更匹配的函数,那么使用函数模板;
3)可以显示的指定一个空的模板参数列表<>,表明必须使用函数模板;
4)普通函数可以进行自动类型转换,函数模板不允许进行自动类型转换;

inline int const& max(int cont& a, int const& b) {
  return a < b ? b: a;
}
template <typename T>
inline T const& max(T const& a,  T const& b) {
   return a < b ? b: a;
}

template <typename T>
inline T const& max(T const& a, T const& b, T const& c) {
   return ::max(::max(a,b),c);
}

int main() {
   ::max(7,42,68);//使用3个参数的函数模板
   ::max(7.0,42.0);//max<double>,实参演绎
   ::max('a','b');//max<char>,实参演绎
   ::max(7,42);//使用int重载的非模板函数
   ::max<>(7,42);//max<int>,实参演绎
   ::max<double>(7,42);// max<double>,没有实参演绎
   ::max('a',42.7);//使用int的非模板函数,并且实参有强制转换

5)重载函数是否可见也会影响实际使用的函数

template <typename T>
inline T const& max(T const& a, T const& b) {
  std::cout<< "max1" << std::endl;
  return a < b? b:a;
}
template <typename T>
inline T const& max(T const& a, T const& b, T const& c) {
  std::cout<< "max2" << std::endl;
  return max(max(a,b),c);//将会使用函数模板,下面的int版本太迟了
}

inline int const& max(int const& a, int const& b) {
  std::cout<< "max3" << std::endl;
  return a < b ? b:a;
}

int main() {
  max(1,2,3);
}

结果:

max2
max1
max1

从结果可以看到,由于3个参数的函数模板还看不到重载的函数,所以使用的还是函数模板。
规则: 函数的所有重载版本的声明,都应该位于该函数被调用的位置之前。否则可能不会被使用

相关文章

网友评论

    本文标题:c++语法系列之7-- 函数模板

    本文链接:https://www.haomeiwen.com/subject/pxsocftx.html