基于循环的范围 - 为什么找不到这些开始/结束函数?

Roe*_*oel 3 c++ c++11

考虑:

#include <iostream>
#include <vector>

class A
{
public:
    typedef bool TAll;
    static TAll All;

    typedef std::vector<int> TVec;
    static TVec m_sVec;

    static TVec::iterator begin() { return m_sVec.begin(); }
    static TVec::iterator end() { return m_sVec.end(); }
};

A::TVec A::m_sVec;
A::TAll A::All;

A::TVec::iterator begin(A::TAll& all) { return A::begin(); }
A::TVec::iterator end(A::TAll& all) { return A::end(); }

int _tmain(int argc, _TCHAR* argv[])
{
    A::m_sVec.push_back(1);
    A::m_sVec.push_back(2);
    A::m_sVec.push_back(3);

    for (auto a : A::All) {
    //for (auto a = begin(A::All); a != end(A::All); a++) {
        std::cout << a << std::endl;
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

具有基于for循环的范围的版本(因此此代码原样)在MSVC2013中给出了以下错误:

1><snip>: error C3312: no callable 'begin' function found for type 'A::TAll'
1><snip>: error C3312: no callable 'end' function found for type 'A::TAll'
Run Code Online (Sandbox Code Playgroud)

海湾合作委员会(4.8.3)说(最后两行):

/usr/include/c++/4.8.3/initializer_list:99:5: note: template<class _Tp> constexpr cons
t _Tp* std::end(std::initializer_list<_Tp>)                                           
     end(initializer_list<_Tp> __ils) noexcept                                        
     ^                                                                                
/usr/include/c++/4.8.3/initializer_list:99:5: note:   template argument deduction/subs
titution failed:                                                                      
main.cpp:31:18: note:   mismatched types 'std::initializer_list<_Tp>' and 'bool'      
  for (int a : A::All) { 
Run Code Online (Sandbox Code Playgroud)

使用函数(被注释​​掉的函数)的'normal'循环工作(当然,在循环内取消引用'a'之后); 我对标准和Stroustroup的理解是它们应该是等价的.但我猜不是.那么这里的问题是什么?谢谢.

Cas*_*sey 6

每个C++ 11 [stmt.ranged]/1,你的循环:

for (auto a : A::All) {
    std::cout << a << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

相当于:

{
    auto && __range = (A::All);
    for ( auto __begin = begin-expr,
               __end = end-expr;
          __begin != __end;
          ++__begin ) {
        auto a = *__begin;
        {
            std::cout << a << std::endl;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

其中表达的确定begin-exprend-expr取决于类型_RangeT初始化表达的A::All(bool在这种情况下):

  • 如果_RangeT是数组类型,...
  • 如果_RangeT是类类型,...
  • 否则,开始-EXPR最终EXPRbegin(__range)end(__range)表示,其中beginend被查找与参数相关的查找(3.4.2) [ 重点加入.出于此名称查找的目的,namespace std是关联的命名空间.

由于bool既不是数组类型也不是类类型,所以第三个子弹适用; 该表达式begin(__range)end(__range),但beginend使用ADL与被解析std为关联的命名空间.每3.4.2 [basic.lookup.argdep]/2:

对于T函数调用中的每个参数类型,都有一组零个或多个关联的命名空间以及一组零个或多个要考虑的关联类.命名空间和类的集合完全由函数参数的类型(以及任何模板模板参数的命名空间)决定.用于指定类型的Typedef名称和using-declarations对此集合没有贡献.[ 强调添加 ]命名空间和类的集合按以下方式确定:

  • 如果T是基本类型,则其关联的命名空间和类集都是空的.
  • ...

所以begin,end只在std命名空间中查找,其中找到了几个声明,但没有一个可以接受类型的参数bool.该计划格式不正确.