​C++类型函数

  • 在C和C++中,我们常见的是 值函数(value function) ,即函数接收的参数是某些值,而且函数的返回结果也是值。
  • 至于 类型函数(value function) ,函数接受类型作为实参,其返回结果是一个类型。

类型函数在编译时求值,标准库提供了大量的类型函数,这些函数可以帮助库的实现者及程序员编写代码时充分利用语言、标准库以及其他代码的优势

类型函数是C++编译时求值机制的一部分,它允许程序进行更严格的类型检查以获取更优的性能。我们把这种用法称之为模板元编程

1.类型函数decltype

int a;

decltype(a) b;//该函数返回其实参a的已声明类型,也就是int,因此这一句就等价于  int b;

关于decltype详细的用法: decltype(expression) var

第一步:如果expression本身是没有带括号的标识符,则var的类型和expression的类型一致,包括const等限定符

double x=5.5;
double y=7.9;
double &rx=x;
const double *pd;

decltype(x) w;//变量w是double类型,
decltype(rx) u=y;//u的类型是double &,作为引用的u必须进行初始化
decltype(pd) v;//v的类型是const double *

第二步,如果expression是一个函数调用,则var与函数的返回类型一致

long indeed(int;//indeed函数的返回值类型是long
decltype(indeed(3)) m;//m的类型是long

需要说明的是:
对于indeed(3),并不会去调用indeed,编译器只是通过查看函数原型来获取返回类型

第三步,当expression是本身是带括号的标识符(expression为左值),则var是指向该类型的引用

double xx=4.4;
int x=5;
const int a=3;
decltype((xx)) r2=xx;//r2的类型是double &,相当于double &r2=xx;因此r2作为引用必须初始化
decltype(w)=xx;//w是double类型

decltype((a)) ct=x;//ct的类型是const int&

第四步,当前面的条件都不满足,则var的类型和expression的类型一致

int t=3;
int &j=t;
int *p=&j;
int &k=j;
int &n=j;

decltype(j+6) i1;//i1的类型是int                             #1
decltype(*p) i2=j; //i2的类型是 int&而非int,因此需要初始化    #2
decltype(&p) i3; // i3的类型是int**                          #3
decltype(100L) i3;//i4的类型是long                           #4  
decltype(k+n) i4;//i5的类型是int                             #5

#1:j虽然是引用,但表达式j+6是一个具体值而非引用,因此decltype(j+6)的结果类型是int
#2:要记住,decltype中如果是解引用操作,那么得到的是引用类型.
#3:根据int **q=&q;  很好理解i3的类型是int **
#4:100L的数据类型是long,那么结果显然就是long
#5:注意,k和n虽然都是对j的引用,但k+n不是引用:它是两个int的和,因此类型
    为int,这和#1的道理一样

2.Iterator_type和Iterator_category

  • 类型函数Iterator_type返回C的 迭代器类型(即C::iterator)
  • 类型函数Iterator_category返回Iter对应的标签来指示提供的是哪种迭代器
void test(vector<string>& v,forward_list<int>& lst){
    sort(v); //我们希望自己编写的sort算法既能排序vector也能排序单向链表
    sort(lst);
}

为此,需要先编写两个辅助函数,它们第三个参数用于区分是用于随机访问迭代器还是前向迭代器

templage <typename Ran>
void sort_helper(Ran beg,Ran end,random_access_iterator_tag){
    sort(beg,end);//标准库的sort算法只能接受随机访问迭代器
}

templage <typename Ran>
void sort_helper(Ran beg,Ran end,forward_iterator_tag){
    vector<decltype(*beg)> v{beg,end};//使用[beg,end)范围内的元素来初始化容器v
    sort(v.begin(),v.end());
    copy(v.begin(),v.end(),beg);//把元素拷回列表
}

现在开始编写自己的sort函数,在这函数中要选择调用哪种辅助函数

templage <typename C>
void sort(C& c){
    using Iter=Iterator_type<C>; //等价于using Iter=typename C::iterator;
    sort_helper(c.begin(),c.end(),Iterator_category<Iter>{});
                  //Iterator_category<Iter>返回Iter对应的标签
}

举例来说明
vector<int> v{2,4,6};
sort(v);//那么上面的C为vector<int>,Iter即为vector<int>::iterator
         // 因此Iterator_category<Iter>{}返回的标签是random_access_iterator_tag
         //至此,调用哪一个版本的set_helper就很明显了

3 类型谓词

类型谓词是一种比较简单的类型函数,在<type_traits>中,标准库定义了大量的类型谓词

is_void<X>                 X是void?
is_integral<X>             X是一个整数类型?
is_floating_point<X>       X是一个浮点数类型 ?  
is_array<X>                X是一个内置数组?
is_arithmetic<X>            X是算术类型?
....

类型萃取返回一个布尔值,为了访问此值,可使用后缀::value,但是不推荐用这种方法

constexpr bool cb1=Is_arithmetic<int>::value;//不推荐用
constexpr bool cb2=Is_arithmetic<int>();//和上面一样,返回一个bool值,而且是
                                          //一个常量表达式。提倡用这个形式

类型谓词常用的场景如下

template <typenae T>
void f(T& t){
// static_assert(std::is_floating_point<T>::value,"FP type expected");  不建议使用加后缀的方法
   static_assert(std::is_floating_point<T>(),"FP type expected");//OK
}1:我们在编译时发现错误,总比在运行时出错要好。静态断言static_assert就能够在对编译时
可知的属性做一些检查一旦发现错误,就以编译器错误消息的形式报告所发现的问题。
static_assert(4<=sizeof(int),"integers are too small");//如果4<=sizeof(int)的结果为false,将
                                                    //输出"integers are too small"信息2static_assert(A,S),其中A必须是个常量表达式,当A为false时,会把S作为一条编译器错误信息输出
constexpr int cei=10;//ci1是常量表达式
const int ci=5;//ci是常量表达式
int i=8;//i不是常量表达式

static_assert(i<cei,"csdnsb");//错误,i不是常量表达式,导致i<cei的结果
                             //也不是常量表达式,毕竟常量表达式的意愿就是在编译时求值
static_assert(ci<cei,"csdnsb");//ok

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这是一个关于 C++ 编程的问题。Person 类有两个属性,姓名和身份证号,其中姓名是指针类型,身份证号是整型。它有三个成员函数,构造函数、析构函数和 Display 函数。CollegeStu 类是由 Person 类派生而来的,它有三个属性,专业、C 程序设计课程成绩和继承自 Person 类的姓名和身份证号。它有一个构造函数和一个 Display 函数。在 main 函数中,我们输入姓名、身份证号、专业和 C 程序设计课程成绩,然后创建一个 CollegeStu 对象并调用它的 Display 函数来输出这些信息。 下面是代码实现: ```cpp #include <iostream> #include <cstring> using namespace std; class Person { protected: char* name; int id; public: Person(char* n, int i) { name = new char[strlen(n) + 1]; strcpy(name, n); id = i; } virtual ~Person() { delete[] name; } virtual void Display() { cout << "Name:" << name << " ID:" << id << " "; } }; class CollegeStu : public Person { private: char* subject; double score; public: CollegeStu(char* n, int i, char* s, double sc) : Person(n, i) { subject = new char[strlen(s) + 1]; strcpy(subject, s); score = sc; } ~CollegeStu() { delete[] subject; } void Display() { Person::Display(); cout << "Subject:" << subject << " C Score:" << score << endl; } }; int main() { char name[81], subject[81]; int id; double score; cin >> name >> id >> subject >> score; CollegeStu cs(name, id, subject, score); cs.Display(); return ; } ``` 输入 "Zhangsan 2 Computer 89.5",输出 "Name:Zhangsan ID:2 Subject:Computer C Score:89.5";输入 "Liuhui 2 Computer 88",输出 "Name:Liuhui ID:2 Subject:Computer C Score:88"。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值