热门关键字:  ubuntu  分区  函数  Fedora  linux系统进程

当前位置 :| 主页>Linux教程>编程开发>

在g++中使用“概念”(concept)检查模板参数

来源: 作者: 时间:2008-10-06 Tag: 点击:

Created: Fang lungang 09/27/2008 Modified: Fang lungang 09/28/2008 16:09>

home

真正的C++程序员应该都用过template,至少是STL。相信大家对模板的编译错误提示印象深刻。

模板编译还有一个特点:没用到就不会去编译(实例化),也就不会检查错误。

“概念(Concept)”本身就是泛型编程的一个重要概念。我的理解:泛型编程就是将算法与具体的数据类型分离;根据算法要求抽象出一个“概念”,任何满足这个“概念”的数据类型的数据都可用这个算法来操作。但是,C++语言本身并不支持“概念”这个特性(新标准里可能会加入)。所以在代码中无法明确体现出对模板参数的要求。

怎么办?在g++带的STL(来自SGI)里部分采用了boost的“Boost Concept Check Library (BCCL)”。

本文不讨论“concept”的理论。只是稍微注释一下boost如何用现有的语言特性模拟的部分“概念”机制,以便大家理解、使用。实现很简单,主要内容都在两个文件里: bits/boost_concept_check.hbits/concept_check.h。我们先看看具体实现,理解之后就知道怎么用了。用起来也很简单。

在函数内检查concept

我们看到 std::min_element 的源码里有对 concept 的要求(注:本文引用的源码都经删节、修改):

template<typename _ForwardIter>
_ForwardIter
min_element(_ForwardIter __first, _ForwardIter __last)
{
// concept requirements
__glibcpp_function_requires(_ForwardIteratorConcept<_ForwardIter>)
__glibcpp_function_requires(_LessThanComparableConcept<
typename iterator_traits<_ForwardIter>::value_type>)
// ...
}

顺藤摸瓜

#ifndef _GLIBCPP_CONCEPT_CHECKS // lgfang:所以编译的时候
// 要-D_GLIBCPP_CONCEPT_CHECKS。但如果
// 直接包含bits/boost_concept_check.h就
// 不需要了,那里面没这个条件预编译。

#define __glibcpp_function_requires(...)
#define __glibcpp_class_requires(_a,_b)

#else // the checks are on

#include <bits/boost_concept_check.h>

#define __glibcpp_function_requires(...) \
__gnu_cxx::__function_requires< __gnu_cxx::__VA_ARGS__ >();
#define __glibcpp_class_requires(_a,_C) \
_GLIBCPP_CLASS_REQUIRES(_a, __gnu_cxx, _C);
#endif // enable/disable
namespace __gnu_cxx { // lgfang: 都算作gnu扩展,所以放在这个namespace

#define _IsUnused __attribute__ ((__unused__))
//lgfang:__attribute__ ((__unused__))是个gnu扩展,用来修饰变量,让
//编译器别因为这个变量没被用到而报错

template <class _Concept>
inline void __function_requires()
//lgfang: 这是一个函数,所以可在函数中使用(被调用),但不能在类定义里
//使用。所以其名字里的 "function" 就是这意思。
{
void (_Concept::*__x)() _IsUnused = &_Concept::__constraints;
// lgfang: 定义了一个变量 __x, 变量的类型是: “_Concept”类的成员函
// 数,且既没有参数也没有返回值的。

// lgfang: 我们就没打算用 __x,所以用 __attribute__ ((__unused__)) 修
// 饰它。

// lgfang: 定义变量 __x 就足以让编译器实例化 _Concept::__constraints
// 了。所以我们要做的是在 _Concept::__constraints 里想办法让编译器实
// 例化所需的接口。下面会以 LessThanComparableConcept 为例。

// lgfang: 已经达到目的了,所以什么操作都不需要做。因而对运行效率影响
// 很小。
}

template <class _Tp>
struct _LessThanComparableConcept // lgfang: 一个concept类的例子。
{
void __constraints() { // lgfang: 从上面分析可知,必须得是这个名字
__aux_require_boolean_expr(__a < __b); // 这是具体的要求;下文还有例子。
}
_Tp __a, __b; // lgfang: 必须是成员变量。如果挪到 __constraints 里就
// 增加了约束条件:有默认构造函数(不论是自己写的还是编
// 译器构造的)。参见:
// http://www.boost.org/doc/libs/1_36_0/libs/concept_check/creating_concepts.htm
};

}

在类定义内检查concept

相关代码如下:

template <typename _Tp, typename _Alloc = allocator<_Tp> >
class deque : protected _Deque_base<_Tp, _Alloc>
{
// concept requirements
__glibcpp_class_requires(_Tp, _SGIAssignableConcept)
// ...
}

#define __glibcpp_class_requires(_a,_C) \
_GLIBCPP_CLASS_REQUIRES(_a, __gnu_cxx, _C);

#define _GLIBCPP_CLASS_REQUIRES(_type_var, _ns, _concept) \
typedef void (_ns::_concept <_type_var>::* _func##_type_var##_concept)(); \
template <_func##_type_var##_concept _Tp1> \
struct _concept_checking##_type_var##_concept { }; \
typedef _concept_checking##_type_var##_concept< \
&_ns::_concept <_type_var>::__constraints> \
_concept_checking_typedef##_type_var##_concept


template <class _Tp>
struct _SGIAssignableConcept
{
void __constraints() {
_Tp __b(__a) _IsUnused;
__a = __a; // require assignment operator
__const_constraints(__a);
}
void __const_constraints(const _Tp& __b) {
_Tp __c(__b) _IsUnused;
__a = __b; // const required for argument to assignment
}
_Tp __a;
};

有了之前的基础,这里只分析宏_GLIBCPP_CLASS_REQUIRES就可以了吧。一行一行来:

最新评论共有 0 位网友发表了评论
发表评论
评论内容:不能超过250字,需审核,请自觉遵守互联网相关政策法规。
用户名: 密码:
匿名?
注册