1

相关:每种范围类型的模板专业化

背景

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

句法

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定义为:

  • If(__range)是一个数组,那么(__range)and (__range + __bound)__bound数组绑定在哪里;
  • 如果(__range)是一个类并且有一个开始或结束成员(或两者都有),那么begin_expris__range.begin()end_expris __range.end();
  • 否则,begin(__range)end(__range),它们是基于与参数相关的查找规则找到的,并std作为关联的命名空间。

问题

给定的类型,我如何编写一些东西来获取基于范围的 for 循环使用的迭代器的类型range_expression?(类似于在给定类型的情况下如何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声明用于声明基类成员。

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

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 魔法?如果不清楚我要完成什么,我会尽量让它更清楚。

4

1 回答 1

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;
}
于 2013-06-19T00:56:54.940 回答