从范围类型中获取迭代器类型

时间:2013-06-18 23:57:15

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

相关: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_traits<Range>::iterator_type的情况下编写Range并将其作为基于范围的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 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魔法?如果我不清楚我想要完成什么,我会尽量让它更清楚。

1 个答案:

答案 0 :(得分: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;
}