简体   繁体   English

基于范围的循环和ADL

[英]Range-based for loops and ADL

The C++0x standard working draft states (section 6.5.4) the following about the begin() and end() calls that are implicit in a range-based for loop: C ++ 0x标准工作草案声明(第6.5.4节)以下关于在基于范围的for循环中隐含的begin()和end()调用:

'begin' and 'end' are looked up with argument-dependent lookup (3.4.2). 使用参数依赖查找(3.4.2)查找'begin'和'end'。 For the purposes of this name lookup, namespace std is an associated namespace. 出于此名称查找的目的,名称空间std是关联的名称空间。

The way I read this, this means that the overload resolution set for the calls to begin() and end() includes all of the following: 我读这个的方式,这意味着为begin()和end()调用设置的重载决议包括以下所有内容:

  • all overloads of begin() and end() that are in scope at the location where the range-based for loop is used (in particular, all overloads in the global namespace will be in scope) begin()和end()的所有重载都在使用基于范围的for循环的位置的范围内(特别是,全局命名空间中的所有重载都在范围内)
  • all overloads of begin() and end() in namespace std 命名空间std中begin()和end()的所有重载
  • all overloads of begin() and end() in other namespaces associated with their arguments 在与其参数关联的其他名称空间中的begin()和end()的所有重载

Is that correct? 那是对的吗?

g++ 4.6's behaviour does not seem to be consistent with this interpretation. g ++ 4.6的行为似乎与这种解释不一致。 For this code: 对于此代码:

#include <utility>

template <typename T, typename U>
T begin(const std::pair<T, U>& p); 

template <typename T, typename U>
U end(const std::pair<T, U>& p); 

int main()
{
    std::pair<int*, int*> p;
    for (int x : p)
        ;
}

It gives the following errors: 它给出了以下错误:

adl1.cpp: In function 'int main()':
adl1.cpp:12:18: error: No match for 'begin(pair<int *, int *> &)'
adl1.cpp:12:18: candidate is:
/usr/local/lib/gcc/i686-pc-linux-
    gnu/4.6.0/../../../../include/c++/4.6.0/initializer_list:86:38: template<
        class _Tp> constexpr const _Tp * begin(initializer_list<_Tp>)
adl1.cpp:12:18: error: No match for 'end(pair<int *, int *> &)'
adl1.cpp:12:18: candidate is:
/usr/local/lib/gcc/i686-pc-linux-
    gnu/4.6.0/../../../../include/c++/4.6.0/initializer_list:96:36: template<
        class _Tp> constexpr const _Tp * end(initializer_list<_Tp>)

This suggests that it is considering only the overloads in namespace std, and not the overloads in the global namespace. 这表明,它正在考虑在空间std重载,而不是在全局命名空间重载。

If, however, I use my own pair class declared in the global namespace, it compiles fine: 但是,如果我使用在全局命名空间中声明的自己的对类,则编译很好:

template <typename T, typename U>
struct my_pair
{
    T first;
    U second;
};

template <typename T, typename U>
T begin(const my_pair<T, U>& p); 

template <typename T, typename U>
U end(const my_pair<T, U>& p); 

int main()
{
    my_pair<int*, int*> p;
    for (int x : p)
        ;
}

As a final test, I tried putting my_pair in a separate namespace: 作为最后的测试,我尝试将my_pair放在一个单独的命名空间中:

namespace my
{

template <typename T, typename U>
struct my_pair
{
    T first;
    U second;
};

}

template <typename T, typename U>
T begin(const my::my_pair<T, U>& p); 

template <typename T, typename U>
U end(const my::my_pair<T, U>& p); 

int main()
{
    my::my_pair<int*, int*> p;
    for (int x : p)
        ;
}

And again I get the errors: 我再次得到错误:

adl3.cpp: In function 'int main()':
adl3.cpp:22:18: error: 'begin' was not declared in this scope
adl3.cpp:22:18: suggested alternative:
adl3.cpp:14:35:   'begin'
adl3.cpp:22:18: error: 'end' was not declared in this scope
adl3.cpp:22:18: suggested alternative:
adl3.cpp:17:33:   'end'

So it seems it is considering only overloads in namespace std and other associated namespaces, and not overloads that are in scope at the call site (the first bullet point in my list above). 因此,它似乎考虑名称空间std和其他相关名称空间中的重载,而不考虑调用站点范围内的重载(上面列表中的第一个项目符号点)。

Is this a gcc bug, or am I misinterpreting the standard? 这是一个gcc错误,还是我误解了标准?

If the latter, does that mean it's impossible to treat an std::pair object as a range in a range-based for loop (without overloading std::begin() and std::end(), which if I'm not mistaken is not allowed)? 如果是后者,这是否意味着将std :: pair对象视为基于范围的for循环中的范围是不可能的(不会重载std :: begin()和std :: end(),如果我不是错误是不允许的)?

I first reported that this looked like a gcc bug to me. 我首先报告说这对我来说就像一个gcc bug。 It now appears that even this part of the for-loop specification is unclear, and an inquiry has been opened on the committee. 现在看来,甚至环路规范的这一部分还不清楚,并且委员会已经开始进行调查。

It still looks like the range-based for-loop rules are going to change very shortly: 看起来基于范围的for循环规则很快就会发生变化:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3257.pdf http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3257.pdf

And I'm not sure which option listed in N3257 will be chosen. 而且我不确定会选择N3257中列出的哪个选项。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM