栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++ 判断类型的结构体

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++ 判断类型的结构体

文章目录
  • __are_same
  • 有默认值的模板结构体
  • 有默认值的模板函数

__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型.​

那么,很显然我们希望写出这么一个模板函数:

template
T f(T x){
    // 如果 T 是 int 型  , 则 return x+1;
    // 否则 return x;
}

问题在于,如何判断 T 是 int 型呢?( T == int 这样的表达式是不合法的)

先来看看解决方案,用到了内置的头文件 ,以及某个东西:
__are_same::__value

#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(判断是否为整数,如short,int,long,unsigned int…等)
__is_floating(判断是否为浮点数,如float,double,long double等)
__is_pointer(判断是否为指针类型,如int*,char*……等)


如果需求是找到判断类型的方法,那么到此为止这篇文章就已经够用了。如果还想知道其内部是如何实现的,那么请继续往下读。

有默认值的模板结构体

首先轻轻点击这个代码溯源到 __are_same的源代码。在我的电脑上,它位于C:MinGWlibgccmingw329.2.0includec++bitscpp_type_traits.h. 这也是我们引用的原因。

// Compare for equality of types.
  template
    struct __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 ,返回值也是 float. 如果传入 x x x 是 double 或 complex,返回值也是 double. 如果传入 x x x 是 long double 或 complex,则返回值为 long double.


也许你会觉得像下面这样复制六个函数,合计六行就搞定了——那这篇文章就白看了。如果要求的是矩阵范数这样复杂的东西,那么肯定不忍心复制六次。

#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的形式,那么就进入第二段的构造,此时complex当中的类型才作为 __type!

#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找到的——结构体内的 __type 类型就是输出类型。



有默认值的模板函数

既然存在「有默认值的模板结构体」,那么如法炮制可以写「有默认值的模板函数」。因此上述的求模长的函数也可以这么写:

// 默认的函数形式
template
T 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型.​
其实现如下:

// 默认的函数形式
template
T f(T x){
    return x;
}

// 特别的函数形式
template<>
int f(int x){
    return x+1;
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/529031.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号