从属名称解析和命名空间标准/标准库

dyp*_*dyp 6 c++ templates token-name-resolution c++11

在回答这个问题时(更好地阅读这个"重复"),我想出了以下解决方案来依赖运营商的名称:

[temp.dep.res]/1:

在解析依赖名称时,会考虑以下来源的名称:

  • 在模板定义点可见的声明.
  • 来自名称空间的声明与实例化上下文(14.6.4.1)和定义上下文中的函数参数的类型相关联.
#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>>{} );
}
Run Code Online (Sandbox Code Playgroud)

但是clang ++ 3.2和g ++ 4.8没有找到这个运算符(名称解析).

是否包含<iterator>定义"模板的定义点" istream_iterator

编辑:正如Andy Prowl所指出的,这与标准库无关,而是与名称查找有关(可以通过模拟标准库中的多个operator>>,至少一个在假名称空间中来证明istream).


Edit2:使用[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>>{} );
}
Run Code Online (Sandbox Code Playgroud)

当然,pair只要变通方法在自定义的命名空间中引入了关联的类,您也可以使用自己的类型operator>>.

And*_*owl 4

这里的问题是,您的调用点operator >>位于std命名空间内的某个位置,而参数类型所在的命名空间是std

假设编译器可以operator >>在调用发生的命名空间或参数类型所在的命名空间(std在本例中都是命名空间)中找到 an ,无论它对于重载解析是否可行(在重载解析之后执行)名称查找),它不会费心寻找operator >>父命名空间中的更多重载。

不幸的是,您operator >>生活在全局命名空间中,因此找不到。