Dependent name resolution and std namespace / Standard Library

Answering this SO question (it is better to read this "duplicate" ), I came up with a solution to the dependent resolution of operator names:

[temp.dep.res] / 1:

When resolving dependent names, names from the following sources are taken into account:

  • Ads that are visible at the template definition point.
  • Declarations from namespaces associated with function argument types both from the creation context (14.6.4.1) and from the definition context.
#include <iostream> #include <utility> // this operator should be called from inside `istream_iterator` std::istream& operator>>(std::istream& s, std::pair<int,int>& p) { s >> p.first >> p.second; return s; } // include definition of `istream_iterator` only after declaring the operator // -> temp.dep.res/1 bullet 1 applies?? #include <iterator> #include <map> #include <fstream> int main() { std::ifstream in("file.in"); std::map<int, int> pp; pp.insert( std::istream_iterator<std::pair<int, int>>{in}, std::istream_iterator<std::pair<int, int>>{} ); } 

But clang ++ 3.2 and g ++ 4.8 did not find this operator (name resolution).

Does the <iterator> definition istream_iterator "template definition point" istream_iterator ?

Edit: since Andy Pull points out that this has nothing to do with the standard library, but rather with a name lookup (you can prove by imitating the standard library with a few operator>> at least one in the istream fake istream ).


Edit2: Workaround using [basic.lookup.argdep] / 2 bullet 2

 #include <iostream> #include <utility> // can include <iterator> already here, // as the definition of a class template member function // is only instantiated when the function is called (or explicit instantiation) // (make sure there are no relevant instantiations before the definition // of the operator>> below) #include <iterator> struct my_int { int m; my_int() : m() {} my_int(int p) : m(p) {} operator int() const { return m; } }; // this operator should be called from inside `istream_iterator` std::istream& operator>>(std::istream& s, std::pair<my_int,my_int>& p) { s >> p.first.m >> p.second.m; return s; } #include <map> #include <fstream> int main() { std::ifstream in("file.in"); std::map<int, int> pp; pp.insert( std::istream_iterator<std::pair<my_int, my_int>>{in}, std::istream_iterator<std::pair<my_int, my_int>>{} ); } 

Of course, you can also use your own pair type if the workaround represents a related class in the user operator>> namespace.

+6
source share
1 answer

The problem is that the point at which your operator >> call is made is somewhere inside the std , and the namespace where the argument types live is std .

If the compiler can find operator >> in the namespace where the call occurs, or in the namespace in which the argument types live (both are the std in this case), regardless of whether it is viable or not to allow overloading (which runs after a name search), it will not look for operator >> overloads in the parent namespaces anymore.

Unfortunately, your operator >> lives in a global namespace and is therefore not found.

+3
source

Source: https://habr.com/ru/post/944997/


All Articles