traits
- traits不是C++关键字或一个预先定义好的构件,是一种技术,也是一个C++程序员共同遵守的协议。该技术要求对内置(built-in)类型和用户自定义类型的表现必须一样好。
- traits允许你在编译期间取得某种类型信息,习惯上traits总被实现为struct。
- 标准技术是把traits放进一个template及其一或多个特化版本中。这样的template在标准程序库中有若干个,其中针对迭代器者被命名为iterator_traits:
- 设计和实现一个traits class的步骤:
- 确认若干你希望将来可取得的类型相关信息。例如,对迭代器而言,我们希望将来可取得其分类(category)
- 为该信息选择一个名称(例如,iterator_category).
- 提供一个template和一组特化版本(例如iterator_traits),内含你希望支持的类型相关信息。
- 以迭代器为例:我们希望取得迭代器的类型,并命名为iterator_category:
STL中的迭代器: | |
---|---|
input | 向前移动,只能读一次 |
output | 向前移动,只能写一次 |
forward | 向前,可读可写一次以上 |
bidirectional | 向前向后,list、set、multiset、map、multimap迭代器 |
random access | 可以执行迭代器算术,vector、deque、string |
template<...>
class deque{
public:
class iterator{
public:
typedef random_access_iterator_tag iterator_category;
};
};
template<...>
class list
public:
class iterator{
public:
typedef bidirectional_iterator_tag iterator_category;
};
};
...//其他迭代器
template<typename IterT>
struct iterator_traits{
typedef typename IterT::iterator_category iterator_category;//条款42:在template中指涉一个嵌套从属类型就必须在其前放置关键字typename.
};
//但对于指针(特殊的迭代器)不能嵌套,因此需要提供偏特化版本,如下:
template<typename IterT>//template偏特化
struct iterator_traits<IterT*>
{
typedef random_access_iterator_tag iterator_category;
};
traits提供的信息也可以作为重载函数的参数,例如:
template<typename IterT , typename DistT> void doSomething(IterT& iter,DistT , std::random_access_iretator_tag){...}//实现random access迭代器 template<typename IterT , typename DistT> void doSomething(IterT& iter,DistT , std::bidirectional_iterator_tag){...}//bidirectional迭代器 ...
traits广泛用于标准程序库,例如还有char_traits用来保存字符类型的相关信息。
TR1导入许多新的traits class用来提供类型信息,包括is_fundamental< T >(判断T是否是内置类型),is_array< T> ,以及is_base_of< T1,T2 >(T1和T2相同,抑或T1是T2的base class)。
Template metaprogramming(TMP,模板元编程)
定义:TMP就是编写基于模板的C++程序并执行于编译期的过程。
可将工作由运行期移往编译器,因而得以实现早期错误侦测和更高的执行效率。
TMP的起手程序(类似于hello world):
//阶乘运算,示范如何通过“递归模板具现化”实现循环
template<unsigned n>
struct factorial{
enum{value = n* factorial<n-1>::value};
};
template<>
struct factorial<0>{
enum{value =1};
};
//每个factorial template具现化都是一个struct,每个struct都使用enum hack声明一个名为value的TMP变量,每个value有其循环内适当值。如果是循环实现的话,可能只存在一个value,并不断更新值。
//调用
int main(){
std::cout<<factorial<5>::value;
}