首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >std::forward_iterator_tag的作用是什么?

std::forward_iterator_tag的作用是什么?
EN

Stack Overflow用户
提问于 2013-07-02 18:12:13
回答 5查看 4.5K关注 0票数 8

在分析应用程序时,我遇到了与gcc 4.7.1一起提供的标准库实现部分。它是include/g++-v4/bits/vector.tcc

代码语言:javascript
复制
template<typename _Tp, typename _Alloc>
template<typename _ForwardIterator>
  void
  vector<_Tp, _Alloc>::
    _M_range_insert(iterator __position, _ForwardIterator __first,
          _ForwardIterator __last, std::forward_iterator_tag)
  {
     …
  }

我注意到函数签名的最后一个参数只是一个标记,我开始想知道它为什么会出现在这里。快速浏览一下this page就会发现std::forward_iterator_tag是一个空结构。它在这里的作用是什么?显然,它对函数是无用的,它可能会浪费一个寄存器或堆栈上的一些空间。那为什么呢?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2013-07-02 18:38:29

简而言之:标签用于重载,用于优化。

以一个简单的advance为例,您可以设计:

代码语言:javascript
复制
template<class II, class D>
void advance(II& i, D n){
    while( n-- ) ++i;
}

但是,它具有O(n)复杂性,这在您使用random_access_iterator时是不可接受的。所以你可以像这样改变你的设计:

代码语言:javascript
复制
template<class II, class D>
void advance_II(II& i, D n){
    while( n-- ) ++i;
}

template<class RAI, class D>
void advance_RAI(RAI& i, D n){
    i += n;
}

template<class II, class D>
void advance(II& i, D n){
    if(is_random_access_iterator(i)) // not yet designed
        advance_RAI(i, n);
    else
        advance_II(i, n);
}

然而,要使用的函数的版本是在运行时决定的,因此我们尝试让编译器在编译时决定选择哪种方法。所以我们给迭代器加上标签。有五个标签:

代码语言:javascript
复制
struct input_iterator_tag {};
struct output_iterator_tag {};
struct forward_iterator_tag : public input_iterator_tag {};
struct bidirection_iterator_tag : public forward_iterator_tag {};
struct random_access_iterator_tag : public bidirection_iterator_tag {};

现在你可以这样做了:

代码语言:javascript
复制
template<class II, class D>
void __advance(II& i, D n, input_iterator_tag){
    while( n-- ) ++i;
}

template<class RAI, class D>
void __advance(RAI& i, D n, random_access_iterator_tag){
    i += n;
}

template<class II, class D>
void advance(II& i, D n){
    __advance(i, n, iterator_traits<II>::iterator_category());
}
票数 11
EN

Stack Overflow用户

发布于 2013-07-02 18:17:43

来区分不同的_M_range_insert重载。

This reference看起来更好一些,并且有一个关于如何使用标签结构的例子。

票数 6
EN

Stack Overflow用户

发布于 2013-07-02 18:16:45

冒着引用你的链接的风险..

将迭代器的类别标识为正向迭代器的

空类:

它被用作标识迭代器类型的标记,以便函数(这里是_M_range_insert )可以适当地执行操作。因为它是一个类型名称,所以可以用来触发不同的重载。

在我的实施中,我有

代码语言:javascript
复制
void _Insert(const_iterator _Where, _Iter _First, _Iter _Last,
            _Int_iterator_tag)

void _Insert(const_iterator _Where, _Iter _First, _Iter _Last,
            input_iterator_tag)

void _Insert(const_iterator _Where, _Iter _First, _Iter _Last, 
            forward_iterator_tag)

在其他重载中。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17422915

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档