C ++在命名空间外找不到函数

时间:2019-02-22 14:31:36

标签: c++ operator-overloading overloading name-lookup

编译以下代码失败,因为第二个函数即使在命名空间之外也找不到第一个。我自己无法解决问题,到目前为止,我在网上都没有找到任何答案。

test.cpp:

#include <bits/stdc++.h>

struct myclass {};

template <typename T, typename U>
std::ostream& operator<< (std::ostream &os, const std::pair<T, U> &p) {
    os << "(" << p.first << ", " << p.second << ")";
    return os;
}

namespace my {
    void operator<< (std::ostream os, myclass m) {
        std::cout << std::pair<int, int>(5, 4); // This is line 13.
    }
}

int main() {
    return 0;
}

编译器(g++ test.cpp -O2 -o test.exe)给出的错误:
test.cpp:13:13: error: no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and 'std::pair<int, int>')
并继续进行,为operator<<可能提供了很多建议。

观察1:如果两个函数的名称不同,则不会发生错误。
观察2:如果删除了namespace my { },则不会发生任何错误。

2 个答案:

答案 0 :(得分:3)

这是一种隐藏名称的方法;函数/运算符不能通过不同的作用域进行重载。

根据name lookup的规则,

(重点是我的)

  

...,名称查找按如下所述检查范围,直到找到至少一个任何类型的声明,然后查找停止并且不再检查其他范围

在这种情况下,名称operator<<在命名空间my(即本身)的范围内找到,然后名称查找停止,将不检查全局范围,而全局{{1 }}不会考虑以下重载解决方案。

还有

  

观察1:如果两个函数的名称不同,则不会发生错误。

这很好,因为没有隐藏名称。

  

观察2:如果删除了我的{}名称空间,则不会发生错误。

这很好,因为两个operator<<被放在相同的范围内,即全局名称空间。然后可以找到两个operator<<,然后以超载分辨率进行考虑,最后将选择适当的一个。

如评论所建议,您可以应用operator<<将全局名称空间中的名称引入名称空间using中;那么将找到两个my,然后将其考虑为过载解析。

答案 1 :(得分:1)

operator<<中定义的namespace my可以防止重载解析考虑您在全局名称空间中定义的operator<<。您只能在此处依赖ADL或在当前范围内带来所需的重载:

namespace my {

std::ostream& operator<<(std::ostream& os, myclass m) {
    // Bringing the operator in the global namespace in the current scope
    using ::operator<<;
    std::cout << std::pair<int, int>(5, 4);
}

}