考虑:
#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的理解是它们应该是等价的。但我猜不是。那么这里的问题是什么?感谢。
答案 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-expr
和end-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)
,但begin
和end
使用ADL解析,std
作为关联的命名空间。每3.4.2 [basic.lookup.argdep] / 2:
对于函数调用中的每个参数类型
T
,都有一组零个或多个关联的命名空间以及一组零个或多个要考虑的关联类。命名空间和类的集合完全由函数参数的类型(以及任何模板模板参数的命名空间)决定。 用于指定类型的Typedef名称和using-declarations对此集合没有贡献。 [强调添加]命名空间和类的集合按以下方式确定:< / p>
- 如果T是基本类型,则其关联的命名空间和类集都是空的。
- ...
所以begin
和end
仅在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风格的行为。很酷。