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作为关联的命名空间。

问题

我应该如何编写一个具有三个特化的模板函数来处理引用的项目符号列表中完全相同的三个案例?

我正在考虑以下内容,但我不确定如何正确执行此操作。

//Handle third bullet - default case
template <typename Range>
void f(Range& range)
{
    for (auto it = begin(range); it != end(range); ++it)
    {
        T& item = *it;
        /* do something custom with item */
    }
}

//Handle first bullet - "range" is an array
template <>
void f<T[]>(T[] range)
{
    auto end = range + sizeof(range)/sizeof(*range);
    for (auto it = range; it != end; ++it)
    {
        T& item = *it;
        /* do something custom with item */
    }
}

//Handle second bullet - "range" with "begin" and/or "end" function
template <>
void f<RangeBE>(RangeBE& range)
{
    //Somehow restrict type RangeBE to classes that have
    //begin or end member functions...
    //Can enable_if be used for this?

    for (auto it = range.begin(); it != range.end(); ++it)
    {
        T& item = *it;
        /* do something custom with item */
    }
}

我完全错误地接近这个吗?这甚至可以用 C++11 做吗(即编译器是否需要做一些特殊的事情来完成这种专业化)?请赐教。:)

一些澄清...

我的问题是如何处理所有三种可能类型的“范围”(来自引用的项目符号列表)作为我编写的函数的输入。(我将使用这里获得的知识来实际编写一个template <typename Range>以相同方式限定的类,其中该类具有处理所有三种类型范围的专业化。)

我的问题不是如何编写一个满足三种可能的“范围”类型之一的类(来自引用的项目符号列表)。有多个关于此的 SO 问题 - 这不是这些问题的重复。

我的问题不是如何使用基于范围的 for 循环。

“仅在“中使用基于范围的 for 循环f不是一个选项或答案。我实际上想要做的是模仿基于范围的 for 循环的语义,但是由于这个问题范围之外的复杂性,我不能简单地在示例函数中使用基于范围的 for 循环f请接受这样一个事实,即我有充分的理由不“只使用基于范围的 for 循环”。解释原因太复杂了。

4

1 回答 1

5

模仿基于范围的 for 循环语义的最简单方法是使用基于范围的 for 循环。但是,由于您的澄清使这不是一种选择,我们想知道您可能打算做什么,那么还有另一种方法:

使用std::beginandstd::end已经表现出您期望的语义,并且是用普通的C++11编写的。记住要启用ADL ,以在基于范围的 for 循环上模仿语义中的第三个项目符号,它最终看起来像这样:

template<typename Range>
void f(Range& range)
{
    using std::begin;
    using std::end;

    for(auto it = begin(range), end_it = end(range); it != end_it; ++it)
    {
        T& item = *it;
        /* do something custom with item */
    }
}

如果你想知道如何std::begin/end工作,那么看看他们的声明:

template< class C >
auto begin( C& c ) -> decltype(c.begin());

此重载是一个函数模板,其中包含一个表达式以推断其返回类型。由于SFINAE,当所述表达式在直接上下文中导致错误时,一旦替换C为实际类型,它就会从重载集中被丢弃(就好像它甚至不存在一样)

template< class T, size_t N >
T* begin( T (&array)[N] );

此重载处理数组情况。请注意,您的方法是不正确的,因为您正在处理一个不完整大小的数组,并且您无法获得其中一个元素的数量。

于 2013-06-18T04:11:30.703 回答