Dependent name resolution & namespace std / 标准库

6

在回答这个stackoverflow问题(最好阅读这个“重复”)时,我想出了以下解决方案来解决运算符的依赖名称解析:

[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>>{} );
}

但是clang++ 3.2和g++ 4.8找不到这个运算符(名称解析)。 < p >包含<iterator>是否定义了模板的“istream_iterator”“定义点”?

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


编辑2:一种解决方法,使用[basic.lookup.argdep] / 2第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>>{} );
}

当然,您也可以使用自己的pair类型,只要解决方法在自定义operator>>的命名空间中引入一个相关联的类即可。
1个回答

4
问题在于你对 operator >> 的调用发生在 std 命名空间内,而参数类型所在的命名空间是 std
只要编译器能够在调用所在的命名空间或参数类型所在的命名空间(这两者都是 std)中找到一个 operator >>,无论它是否适用于重载决议(在名称查找之后执行),它都不会再去查找父命名空间中的更多重载函数。
不幸的是,你的 operator >> 存在于全局命名空间中,因此无法找到。

请问能提供一个参考文献吗? :) 我很想在标准中查找。 - dyp
好的,我明白了 :) [basic.lookup.unqual]/1; 在相关联的命名空间中查找/参数依赖查找在这里不起作用,因为两种类型都来自于namespace std - dyp
据我所知,唯一相关的命名空间是 namespace std,而我不想在其中注入运算符。 - dyp
@DyP:哦,好的,我误解了你的句子。 - Andy Prowl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接