- __are_same
- 有默认值的模板结构体
- 有默认值的模板函数
C++模板template的存在,为重载函数提供了很多方便。但有些时候我们要对不同的类型作不同的处理(比如整型与浮点型、实数与复数)。比如我要实现如下函数:
f
(
x
)
=
{
x
+
1
,
x
是
i
n
t
型
,
x
,
x
非
i
n
t
型
.
f(x)= left{ begin{array}{ll} x+1 & ,x是int型, \ x & ,x非int型. end{array} right.
f(x)={x+1x,x是int型,,x非int型.
那么,很显然我们希望写出这么一个模板函数:
templateT f(T x){ // 如果 T 是 int 型 , 则 return x+1; // 否则 return x; }
问题在于,如何判断 T 是 int 型呢?( T == int 这样的表达式是不合法的)
先来看看解决方案,用到了内置的头文件
__are_same
#include#include using namespace std; template T f(T x){ if (__are_same ::__value == true){ return x+1; }// else return x; } int main(){ cout << "f(5) = " << f(5) << endl; // 6 cout << "f(5.0) = " << f(5.0f) << endl; // 5 return 0; }
从效果来看,很容易看懂这个东西判断 T 和 int 是否为同一类型,如果是,则 __value为true,否则 __value 为false.
C++还有类似的其它结构体,比如:
__is_integer
__is_floating
__is_pointer
如果需求是找到判断类型的方法,那么到此为止这篇文章就已经够用了。如果还想知道其内部是如何实现的,那么请继续往下读。
有默认值的模板结构体
首先轻轻点击这个代码溯源到 __are_same的源代码。在我的电脑上,它位于C:MinGWlibgccmingw329.2.0includec++bitscpp_type_traits.h. 这也是我们引用
// Compare for equality of types. templatestruct __are_same { enum { __value = 0 }; typedef __false_type __type; }; template struct __are_same<_Tp, _Tp> { enum { __value = 1 }; typedef __true_type __type; };
这定义了两段 __are_same,可以看出它们都是结构体。但为什么有两段呢?
解释:
第一段是 __are_same 的默认构造。
第二段是 __are_same 的特别构造。即,如果传入的typename刚好符合第二段,那就用第二段来构造。
在代码上有个区别两者的细节,那就是:第一段 __are_same后面没有尖括号<>,但第二段有!
在此处,如果传入 __are_same 的两个类型刚好一样,那就满足第二段的构造,里面的 __value 就是1 (true) ;否则(类型不一样时)默认用第一段构造,__value 值为0.
其实我们也可以自定义一个玩玩。比如一个更实用的例子:实现 f ( x ) f(x) f(x)计算一个复数或实数 x x x的模长 ∣ x ∣ |x| ∣x∣。要求保持精度。
保持精度,即:如果传入
x
x
x 是 float 或 complex
也许你会觉得像下面这样复制六个函数,合计六行就搞定了——那这篇文章就白看了。如果要求的是矩阵范数这样复杂的东西,那么肯定不忍心复制六次。
#include#include using namespace std; float f(float x) { return abs(x);} double f(double x) { return abs(x);} long double f(long double x) { return abs(x);} complex f(complex x) { return sqrt(real(x)*real(x)+imag(x)*imag(x));} complex f(complex x) { return sqrt(real(x)*real(x)+imag(x)*imag(x));} complex f(complex x){ return sqrt(real(x)*real(x)+imag(x)*imag(x));}
我们的应对策略如下:
创建一个 __typeHelper 结构体,其默认值 __is_complex = 0, 类型 __type 为输入的类型。
但是,当输入的东西刚好可以写成 complex
#include#include #include #include using namespace std; template struct __typeHelper{ enum { __is_complex = 0}; typedef T __type; }; template struct __typeHelper >{ enum { __is_complex = 1}; typedef T __type; }; //求模长的函数 f template typename __typeHelper ::__type f(T x){ return sqrt(real(x)*real(x)+imag(x)*imag(x)); } int main(){ cout << f(complex (3.0,4.0)); // 5 return 0; }
最后函数f,输入类型为 T,输出类型是根据结构体 __typeHelper
有默认值的模板函数
既然存在「有默认值的模板结构体」,那么如法炮制可以写「有默认值的模板函数」。因此上述的求模长的函数也可以这么写:
// 默认的函数形式 templateT f(T x){ return abs(x); } // 如果是 complex,则会自动采用如下函数 template T f(complex x){ return sqrt(real(x)*real(x)+imag(x)*imag(x)); }
而对于第一例,
f
(
x
)
=
{
x
+
1
,
x
是
i
n
t
型
,
x
,
x
非
i
n
t
型
.
f(x)= left{ begin{array}{ll} x+1 & ,x是int型, \ x & ,x非int型. end{array} right.
f(x)={x+1x,x是int型,,x非int型.
其实现如下:
// 默认的函数形式 templateT f(T x){ return x; } // 特别的函数形式 template<> int f(int x){ return x+1; }



