Why doesn't range-for find my overloads of begin and end for std::istream_iterator?

我们两清 提交于 2019-11-30 12:55:13

Ranged-for relies on ADL if the special handling for native array (T foo[N]) and member begin/end doesn't yield any results.

§6.5.4 [stmt.ranged] p1

  • otherwise, begin-expr and end-expr are begin(__range) and end(__range), respectively, where begin and end are looked up with argument-dependent lookup (3.4.2). For the purposes of this name lookup, namespace std is an associated namespace.

Your problem is, that the associated namespace of std::istream_iterator is (obviously) namespace std, not the global namespace.

§3.4.2 [basic.lookup.argdep] p2

For each argument type T in the function call, there is a set of zero or more associated namespaces and a set of zero or more associated classes to be considered. The sets of namespaces and classes is determined entirely by the types of the function arguments [...].

  • If T is a fundamental type, its associated sets of namespaces and classes are both empty.
  • If T is a class type (including unions), its associated classes are: the class itself; the class of which it is a member, if any; and its direct and indirect base classes. Its associated namespaces are the namespaces of which its associated classes are members. Furthermore, if T is a class template specialization, its associated namespaces and classes also include: the namespaces and classes associated with the types of the template arguments provided for template type parameters [...].

Note the last (quoted) part of the second bullet. It basically means that using a class which is a member of the global namespace as the template argument makes the code work:

#include <iterator>
#include <iostream>

template<class T>
std::istream_iterator<T> begin(std::istream_iterator<T> is){
  return is;
}
template<class T>
std::istream_iterator<T> end(std::istream_iterator<T>){
  return std::istream_iterator<T>();
}

struct foo{};

std::istream& operator>>(std::istream& is, foo){
  return is;
}

int main(){
  for(foo f : std::istream_iterator<foo>(std::cin))
  //                                ^^^
  // make global namespace one of the associated namespaces
    ;
}

Because of argument depended lookup the compiler tries to find begin() and end() in the std namespace. If you put your functions there, the code compiles.

Since name lookup is a complicated issue in C++ I'm not entirely sure if the compiler is behaving correctly or not.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!