【C++】traits classes

程序开发时,经常遇到根据变量获取其类型信息的需求.

例如,某一个函数针对不同的类型参取了不同的优化策略,因而要获取相应的类型信息调用对应的函数.

template<typename IterT,typename DistT> //将迭代器向前移动d单位
void advance(IterT& iter,DistT d);        //如果d < 0则向后移动

观念上advance只是做iter += d动作,但其实不可以全然那么实践.因为只有random access迭代器才支持+=操作,面对其他威力不那么强大迭代器种,advance必须反复施行++或--,共d次.因而希望其实现方式如下:

template<typename IterT,typename DistT>
void advance(IterT& iter,DistT d)
{
    if(iter is a random access iterator) {
        iter += d;        //针对random access 迭代器使用迭代器算术运算
    }
    else{        //针对其他迭代器分类,反复调用++或--
        if(d >= 0) {while(d--) ++iter;}    
        else {while(d++) --iter;}    
    }
}

其中,关键是如何判断类型为IterT的iter是否为random access迭代器

初步想法,可以在类型中定义相应的类型信息属性,标识该类型所包含的类型信息,然后通过获取该类型的这些信息属性,进行判断.

这种想法,可以解决自定义类型的问题,但无法解决内置类型的问题,因为我们无法将信息嵌套于原始指针内.

因此,上述想法行不通,我们需要把类型的类型信息放于类型自身之外.

traits classes就是一种技术,也是个C++程序员共同遵守的协底色,它要求对内置类型和用户自定义类型表现一样.

这种技术可以允许我们在编译期间取得某些类型信息.一个traits class设计与实现的一般步骤如下:

1.确认若干你希望将来可取得的类型相关信息.

2.为该信息选择一个名称

3.提供一个template和一组特化版本,内含你希望支持的类型相关信息.

有了相关的trait class,我们可以用trait class提供的信息类型,取代if语句中的条件判断.

这样实现,将会存在一个问题,编译期完成的事被延到运行期了.

这是因为traits class可以在编译期间获知IterT的类型,但if语句却是在运行期才会判断.

这里就需要一种方法,可以在编译期完成类型的判断,取代if语句的判断.

该方法就是重载,根据编译期间确定的类型信息,选择最合适的重载函数,相当根据if语句判断后,再选择具体的实现.

template<typename IterT,typename DistT>
void doAdvance(IterT& iter,DistT d,std::random_access_iterator_tag)
{
    iter += d;
}
template<typename IterT,typename DistT>
void doAdvance(IterT& iter,DistT d,std::bidirectional_iterator_tag)
{
    if(d >= 0) {while(d--) ++iter;}    
    else {while(d++) --iter;}    
}
template<typename IterT,typename DistT>
void doAdvance(IterT& iter,DistT d,std::input_iterator_tag)
{
    if(d < 0){
        throw std::out_of_range("Negative distance");
    }
    while(d--) ++iter;
}

template<typename IterT,typename DistT>
void advance(IterT& iter,DistT d)
{
    doAdvance(iter,d,typename std::iterator_traits<IterT>::iterator_category());
}

trait class具体的使用方法,如上述代所述.

1.建立一组重载函数或函数模板,彼此间的差异只在于各自的traits参数.令每个函数实现码与其接受的traits信息相匹配.

2.建立一个控制函数或函数模板,它调用上述的那些重载函数并传递traits class所提供的信息.

启发:解决问题时,思路的逐步深入,遇到问题,可以先想个初步思路,然后分析初步思路不足,并改进初步思路,提供合理的解决方案.

参考资料:Effective C++

posted @ 2012-07-16 10:10  一点心青  阅读(1636)  评论(0编辑  收藏  举报