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

时间:2015-01-13 23:20:46

标签: 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;
}

具有基于for循环的范围的版本(所以此代码为as-is)在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'
GCC(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) { 

正常&#39; for循环使用函数(被注释​​掉的函数)可以正常工作(当然,在解除引用&#39; a&#39;在循环中);我对标准和Stroustroup的理解是它们应该是等价的。但我猜不是。那么这里的问题是什么?感谢。

2 个答案:

答案 0 :(得分:6)

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

for (auto a : A::All) {
    std::cout << a << std::endl;
}

相当于:

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

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

  
      
  • 如果_RangeT是数组类型,...
  •   
  • 如果_RangeT是类类型,...
  •   
  • 否则, begin-expr end-expr 分别为begin(__range)end(__range),其中 begin并且使用参数依赖查找(3.4.2) [强调添加]查找end。出于此名称查找的目的,名称空间std是关联的名称空间。
  •   

由于bool既不是数组类型,也不是类类型,因此适用第三个项目符号;表达式为begin(__range)end(__range),但beginend使用ADL解析,std作为关联的命名空间。每3.4.2 [basic.lookup.argdep] / 2:

  

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

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

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

答案 1 :(得分:0)

对于那些想知道重点是什么的人,请考虑以下略显抽象的例子:

#include <iostream>
#include <vector>
#include <string>
#include <xfunctional>

#include <boost/iterator/filter_iterator.hpp>

struct Employee
{
    std::string name;
    int age;
    operator int() { return age; }
};

class Employees
{
public:
    struct TOlderThan {
        int m_MinimumAge;
        TOlderThan& operator()(int age)
        {
            m_MinimumAge = age;
            return *this;
        }
    };
    static TOlderThan OlderThan;

    typedef std::vector<Employee> TEmployees;
    static TEmployees sEmployees;

    static TEmployees::iterator begin() { return sEmployees.begin(); }
    static TEmployees::iterator end() { return sEmployees.end(); }
};

Employees::TEmployees Employees::sEmployees;
Employees::TOlderThan Employees::OlderThan;

typedef boost::filter_iterator<std::binder1st<std::less<int>>, Employees::TEmployees::iterator> TFilter;
TFilter begin(const Employees::TOlderThan& min_age) { return boost::make_filter_iterator(std::bind1st(std::less<int>(), min_age.m_MinimumAge), Employees::begin(), Employees::end()); }
TFilter end(const Employees::TOlderThan& min_age) { return boost::make_filter_iterator(std::bind1st(std::less<int>(), min_age.m_MinimumAge), Employees::end(), Employees::end()); }

int main(int argc, _char* argv[])
{
    Employees::sEmployees.push_back({"John", 34});
    Employees::sEmployees.push_back({"Pete", 48});
    Employees::sEmployees.push_back({"Jake", 59});

    for (Employee& e : Employees::OlderThan(40)) {
        std::cout << e.name << std::endl;
    }

    return 0;
}

按预期输出

Pete
Jake

基本上,此功能允许您使用少于10行代码在您的API中构建几乎DSL风格的行为。很酷。