STL中的check

很早之前,忘了是看书还是别人介绍了,说STL里有一些类型检查的东西,比如vector里面会检查是否定义了赋值操作符,还有的检查是否有默认参数的构造函数之类的。看STL源码的时候发现了一个concept_check的头文件,发现其中的内容还真是不少。有一些就是做这种检查的。

STL默认提供了很多种操作的检查,比如:

_Allocator

_Assignable

_DefaultConstructible

_EqualityComparable

_LessThanComparable

_TrivialIterator

_InputIterator

_OutputIterator

_ForwardIterator

_BidirectionalIterator

_RandomAccessIterator

_Mutable_TrivialIterator

_Mutable_ForwardIterator

_Mutable_BidirectionalIterator

_Mutable_RandomAccessIterator

现在来看看是怎么实现的。

举个例子,一个C++的类TesetClass,如果我没有重写operator=,默认是由编译器提供一个。而如果我写了这个函数,但是没有实现,并且把它写为private,这也算是一个常用的手法。这种情况下,如何去检查出来?很简单,如果我们定义它的一个对象a1,再定义一个对象a2,如果调用a1=a2,编译器就会报错,提示我们赋值操作符为私有,没有实现。很好,STL中也是采用类似的方式。来看下它是怎么做的。

在此,也以赋值操作符为例。

在vector中可以看到如下的一句代码:

__STL_CLASS_REQUIRES(_Tp, _Assignable);

找到宏定义:

#define __STL_CLASS_REQUIRES(__type_var, __concept)   typedef void (* __func##__type_var##__concept)( __type_var );   template <__func##__type_var##__concept _Tp1>   struct __dummy_struct_##__type_var##__concept { };   static __dummy_struct_##__type_var##__concept<     __concept##_concept_specification<       __type_var>::__concept##_requirement_violation>    __dummy_ptr_##__type_var##__concept

分析一下,typedef void (* __func##__type_var##__concept)( __type_var ); 定义了一个函数指针,参数是__type_var。

 template <__func##__type_var##__concept _Tp1>
  struct __dummy_struct_##__type_var##__concept { }; 

上面两句定义了一个模板类,不要小看它,可是大有作为的。它的模板参数呢,就是上面定义的函数指针

static __dummy_struct_##__type_var##__concept<     __concept##_concept_specification<       __type_var>::__concept##_requirement_violation>    __dummy_ptr_##__type_var##__concept

定义了前面提到的模板类的一个对象。这个模板对象的模板实参呢,就是下面即将提到的,STL定义好的函数,而这个函数就是用于检查赋值操作符的。这句中__concept##_concept_specification< __type_var>::__concept##_requirement_violation整体是模板实参,也就是一个函数指针,而这个模板实参又是用的一个模板。__concept##_requirement_violation函数,是模板类__concept##_concept_specification< __type_var>的一个函数。下面我们继续上代码,现在越来越清晰了。

代入_Assignable,来看下。

template <class _Type>
struct _Assignable_concept_specification {
  static void _Assignable_requirement_violation(_Type __a) {
    _STL_ERROR::__assignment_operator_requirement_violation(__a);
    _STL_ERROR::__copy_constructor_requirement_violation(__a);
    _STL_ERROR::__const_parameter_required_for_copy_constructor(__a,__a);
    _STL_ERROR::__const_parameter_required_for_assignment_operator(__a,__a);
  }
};

模板类_Assignable_concept_specification其实就是上面的__concept##_concept_specification< __type_var>,它的函数_Assignable_requirement_violation其实就是__concept##_requirement_violation了。现在都已经清楚了。但是具体内容还没有,别着急,谜底马上揭晓。

struct _STL_ERROR {
template <class _Type>
  static _Type
  __assignment_operator_requirement_violation(_Type __a) {
    __a = __a;
    return __a;
  }
}

这里就值给出了一个函数的实现,不过已经能够充分说明问题了。这个函数调用了赋值操作!还记得我们是怎么判断赋值操作的吧,就是这样子,是不是很简单?

一个静态模板对象传递一个模板类型的函数,这个函数调用会检查赋值操作,当然不止是赋值操作,文章最开始提到的几种操作都包含。

不过得说一下一个令人沮丧的结果,我在vc2010中采用如是方式进行验证,发现编译器并不会报错,然而使用g++编译时则会报错。看来不同的编译器是做了不同的处理的。

时间: 2024-10-05 06:17:41

STL中的check的相关文章

C++ STL中Map的按Key排序和按Value排序

原文  http://blog.csdn.net/iicy266/article/details/11906189 map是用来存放<key, value>键值对的数据结构,可以很方便快速的根据key查到相应的value.假如存储学生和其成绩(假定不存在重名,当然可以对重名加以区分),我们用map来进行存储就是个不错的选择. 我们这样定义,map<string, int>,其中学生姓名用string类型,作为Key:该学生的成绩用int类型,作为value.这样一来,我们可以根据学

STL中的nth_element()方法的使用

STL中的nth_element()方法的使用 通过调用nth_element(start, start+n, end) 方法可以使第n大元素处于第n位置(从0开始,其位置是下标为 n的元素),并且比这个元素小的元素都排在这个元素之前,比这个元素大的元素都排在这个元素之后,但不能保证他们是有序的,下面是这个方法的具体使用方法. 1 #include <iostream> 2 3 #include <algorithm> 4 5 #include <functional>

STL中的Vector相关用法

STL中的Vector相关用法 标准库vector类型使用需要的头文件:#include <vector>. vector 是一个类模板,不是一种数据类型,vector<int>是一种数据类型. Vector的存储空间是连续的,list不是连续存储的. 1. 定义和初始化 vector< typeName > v1; //默认v1为空,故下面的赋值是错误的v1[0]=5;//v2是v1的一个副本,若v1.size()>v2.size()则赋值后v2.size()被

STL中的set容器的一点总结2

http://blog.csdn.net/sunshinewave/article/details/8068326 1.关于set C++ STL 之所以得到广泛的赞誉,也被很多人使用,不只是提供了像vector, string, list等方便的容器,更重要的是STL封装了许多复杂的数据结构算法和大量常用数据结构操作.vector封装数组,list封装了链表,map和set封装了二叉树等,在封装这些数据结构的时候,STL按照程序员的使用习惯,以成员函数方式提供的常用操作,如:插入.排序.删除.

STL中map的用法

map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完成有可能在我们处理一对一数据的时候,在编程上提供快速通道.这里说下map内部数据的组织,map内部自建一颗红黑树(一种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的,后边我们会见识到有序的好处. 下面举例说明什么是一对一的数据映射.比如一个班级中,每个学生的学号跟他的姓名就存在着一一

stl中char 与wchar 的转换

学习记录: stl中 字符串 str自然对应的是string 宽字符串wchar 对应的是wstring 宽字符串占用两个字节 两者的转换有三种办法 1 windows 的api转换函数WideCharToMultiByte()与MultiByteToWideChar(). 不适合跨平台使用. 2 ATL中CA2W类与CW2A类.或者使用A2W宏与W2A宏.稍显累赘和麻烦 3 使用CRT库的函数 函数和使用方法见下列代码 #include <string> #include <iostr

c++ STL中的vector与list为什么没有提供find操作?

map里有,set里也有,vector,list没有,太不公平了吧. 其实应该考虑为什么map,set里有find操作. include<algorithm>里有通用的find操作,通用的find内部是从begin到end进行一次遍历,复杂度是O(n). 通过iterator从begin到end遍历map与set时,得到的结果是按key排序的结果,而不是插入时的顺序(所以这两个容器没有push_back操作), 其实,insert到map与set中的元素会被组织到一颗红黑树上,红黑树是一颗平衡

Binary Search 的递归与迭代实现及STL中的搜索相关内容

与排序算法不同,搜索算法是比较统一的,常用的搜索除hash外仅有两种,包括不需要排序的线性搜索和需要排序的binary search. 首先介绍一下binary search,其原理很直接,不断地选取有序数组的组中值,比较组中值与目标的大小,继续搜索目标所在的一半,直到找到目标,递归算法可以很直观的表现这个描述: int binarySearchRecursive(int A[], int low, int high, int key) { if (low > high) return -1;

浅谈C++ STL中的优先队列(priority_queue)

从我以前的博文能看出来,我是一个队列爱好者,很多并不是一定需要用队列实现的算法我也会采用队列实现,主要是由于队列和人的直觉思维的一致性导致的. 今天讲一讲优先队列(priority_queue),实际上,它的本质就是一个heap,我从STL中扒出了它的实现代码,大家可以参考一下. 首先函数在头文件<queue>中,归属于命名空间std,使用的时候需要注意. 队列有两种常用的声明方式: std::priority_queue<T> pq; std::priority_queue<