本文介绍了基于范围的循环和ADL的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

状态(第6.5.4节)以下关于在基于范围的for循环中隐含的begin()和end()调用:

我读这个的方式,这意味着为begin()和end()调用设置的重载解析包括以下所有内容:

$ ul

  • 在范围内使用基于范围的for循环的位置(尤其是全局名称空间中的所有重载将在作用域中)的begin()和end()的所有重载。
  • 命名空间中的begin()和end()的所有重载

  • 与其参数相关的其他命名空间中的所有begin()和end b

    $ b

    是否正确?

    g ++ 4.6的行为似乎并不符合这个解释。对于这个代码:

      #include< utility> 

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

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

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



    $ b $ p
    $ p






    $ $ b

      adl1.cpp:在函数'int main()':
    adl1.cpp:12:18:error:'begin(pair< int *,int *>&)'
    adl1.cpp:12:18:candidate:
    / 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:错误:不匹配'end(pair< int *,int *>)'
    adl1。 cpp:12:18:应聘者是:
    / 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(ini​​tializer_list< _Tp>)

    这表示它正在考虑 在命名空间std中的重载,而不是在全局命名空间中的重载。

    然而,如果我使用我自己在全局命名空间中声明的pair类,它编译得很好:

     模板< typename T,typename U> 
    struct my_pair
    {
    第一个;
    U秒;
    };

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

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

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



    $ b $ p
    $ b

    作为最后的测试,我试着把my_pair放在一个单独的命名空间中: p>

      namespace my 
    {

    模板< typename T,typename U>
    struct my_pair
    {
    第一个;
    U秒;
    };

    }

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

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

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

    再次遇到错误:

      adl3.cpp:在函数'int main()':
    adl3.cpp:22:18:error:'begin'was not declare in this范围
    adl3.cpp:22:18:建议替代:
    adl3.cpp:14:35:'begin'
    adl3.cpp:22:18:错误:'end'不是在此范围内声明
    adl3.cpp:22:18:建议替代:
    adl3.cpp:17:33:'end'
    重载,而不是呼叫站点范围内的重载(第一个这是一个海湾合作委员会的错误,或者我误解了标准?



    如果是后者,是否意味着不可能把std :: pair对象作为基于范围for循环的范围(不要重载std :: begin()和std :: end(),如果我不会误认为是不允许的)?


    它仍然看起来像是基于范围的回环规则将会很快改变:



    我不确定在N3257中列出哪个选项会被选中。


    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:

    The way I read this, this means that the overload resolution set for the calls to begin() and end() includes all of the following:

    • 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)
    • all overloads of begin() and end() in namespace std
    • all overloads of begin() and end() in other namespaces associated with their arguments

    Is that correct?

    g++ 4.6's behaviour does not seem to be consistent with this interpretation. 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.

    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:

    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).

    Is this a gcc bug, or am I misinterpreting the standard?

    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)?

    解决方案

    I first reported that this looked like a gcc bug to me. 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:

    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.

    这篇关于基于范围的循环和ADL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

  • 09-05 04:39
    查看更多