【问题标题】:Get Iterator Type from Range Type从范围类型获取迭代器类型
【发布时间】:2013-06-15 09:00:24
【问题描述】:

相关:Template Specialization for each Range Type

背景

在 C++11 中,基于范围的 for 循环处理三种“范围”,概括为 here (link)。我在下面引用了相关部分。

语法

for (range_declaration : range_expression) loop_statement

说明

上述语法产生类似于以下的代码(__range__begin__end 仅用于说明):

{
     auto && __range = range_expression;
     for (auto __begin = begin_expr,
         __end = end_expr;
         __begin != __end; ++__begin) {
         range_declaration = *__begin;
         loop_statement
     }
}

评估range_expression 以确定将被迭代的序列或范围。序列的每个元素都被取消引用,并使用range_declaration 中给出的类型和名称分配给变量。

begin_exprend_expr 被定义为:

  • 如果(__range)是一个数组,那么(__range)(__range + __bound),其中__bound是数组绑定;
  • 如果(__range) 是一个类并且有一个开始或结束成员(或两者都有),那么begin_expr__range.begin() 并且end_expr__range.end()
  • 否则,begin(__range)end(__range),它们是根据与参数相关的查找规则找到的,std 作为关联的命名空间。

问题

在给定 range_expression 的类型的情况下,我如何编写一些东西来获取基于范围的 for 循环使用的迭代器的类型? (类似于std::iterator_traits<Iterator>::value_type 在给定Iterator 类型的情况下获取迭代器值的类型。)

我希望能够在给定某个范围类型 Range 的情况下编写 range_traits<Range>::iterator_type,并将其作为基于范围的 for 循环将使用的迭代器类型。

我试过了:

template <typename Range>
struct range_traits
{
    //Try to use ADL to get correct "begin" function, or std::begin by default
    using std::begin;
    typedef typename decltype(begin(std::declval<Range>())) iterator_type;
};

但是,这不起作用,因为在类主体中的 using 声明的上下文中,using 声明用于声明基类成员。

以下确实有效,因为using std::begin 可以满足我的要求(如果ADL 失败,则将std::begin 设为默认值)。

template <typename Range>
void example(Range& range)
{
    using std::begin;
    auto it = begin(range); //it is of the type I want
    //the expression decltype(begin(range)) would get the type I want
}

问题是我实际上无法从函数体中“取出”类型。

关于如何完成这项任务的任何想法?是否有一些可以使用的 SFINAE 魔法?如果不清楚我要完成什么,我会尽量让它更清楚。

【问题讨论】:

标签: c++ templates c++11 iterator


【解决方案1】:

这似乎工作正常:

#include <iterator>

namespace range_trait_namespace {
  using std::begin;
  template<typename Range>struct range_traits {
    typedef decltype(begin(std::declval<Range>())) iterator_type;
  };
}


#include <iostream>
#include <vector>

int main(int, char**) {
  std::cout << "oi\n";
  std::vector<int> i { 1, 2, 3, };
  for( auto x: i )
    std::cout << x << "\n";
  for( range_trait_namespace::range_traits<std::vector<int>>::iterator_type aa = i.begin(); aa != i.end(); ++aa)
    std::cout << *aa << "\n";
  return 0;
}

【讨论】:

  • 正是我最终使用的。我是根据评论自己得出的(看起来这实际上是一个重复的问题)-但无论如何我都会将此标记为答案。
猜你喜欢
  • 2011-03-02
  • 1970-01-01
  • 1970-01-01
  • 2017-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-26
  • 2011-12-04
相关资源
最近更新 更多