Effective C++(使用traits classes表现类型信息)


author:

  • luixiao1223
    title: 使用traits classes表现类型信息

工具性templates

advance,可以将迭代器移动某个距离.

template<typename IterT, typename DistT>
void advance(IterT& iter, DistT d); // 如果d<0则可以向后移动.

STL的迭代器分类

一次一步,只能读取(写入)一次

  1. istream_iterators
  2. ostream_iterators

forward 迭代器

每次移动一个位置,但是可以读取多次.STL没有这种,有的实现了单链表的slist

bidirectional

可以向前向后移动一个位置,可以读取多次.set,multiset,map,multimap,list

random access

可以进行迭代算术,可以一次性移动多个距离.vector,deque,string.

如何实现advance

这是伪代码的实现思路

template<typename IterT, typename DistT>
void advance(IterT& iter, DistT d)
{
    if (iter is a random access iterator) {
        iter += d;
    }
    else {
        if (d >= 0) { while (d--) ++iter; }
        else { while (d++) --iter; }
    }
}

如何判断类的所属类型?实际上STL中有tag信息.可以使用tag信息

struct input_iterator_tag {};
struct output_iterator_tag {};
struct forward_iterator_tag: public input_iterator_tag {};
struct bidirectional_iterator_tag: public forward_iterator_tag {};
struct random_access_iterator_tag: public bidirectional_iterator_tag {};

template<typename IterT>
struct iterator_traits;

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; //获取内类型中的tag类型
};

// 用户自定义类型可以使用
template<typename T>
struct iterator_traits<T*>
{
    typedef random_access_iterator_tag iterator_category; // 把指针的tag类型设置为random access
};

来实现advance看看

template<typename IterT, typename DistT>
void advance(IterT& iter, DistT d)
{
    if (typeid(typename std::iterator_traits<IterT>::iterator_category) ==
        typeid(std::random_access_iterator_tag))
        ...;
}

有编译的问题.
typeid时发生在运行期.而其他的事情时可以在编译期完成的.所以这样的设计本身就浪费了.如何提前到编译期来?
函数重载

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()
        );
}

这样就可以顺利的利用重载函数在编译期就确定要运行的时循环++还是直接+d.

TR1

这里面有很多关于traits的相关功能如
is_fundamental<T>, is_array<T>,is_base_of<T1,T2> 等等

发布了127 篇原创文章 · 获赞 11 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/luixiao1220/article/details/104277951
今日推荐