【问题标题】:C++ can't find function out of namespaceC++ 在命名空间中找不到函数
【发布时间】:2019-07-16 16:18:55
【问题描述】:

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

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&lt;&lt;' (operand types are 'std::ostream {aka std::basic_ostream&lt;char&gt;}' and 'std::pair&lt;int, int&gt;').
它继续,给出了一长串关于operator&lt;&lt;可能意味着什么的建议。

观察1:如果两个函数名称不同,不会出错。
观察2:如果namespace my {去掉},不会出错发生。

【问题讨论】:

  • 通过显式调用全局运算符:::operator&lt;&lt;(std::cout, std::pair&lt;int, int&gt;(5, 4)); 它应该可以工作,但这非常丑陋(并且不可链接)。如果有更好的方法,我不会将其发布为答案。
  • 更好的方法是在调用前使用 using 指令 ​​(using ::operator&lt;&lt;;)。至于为什么查找最终没有在全局命名空间中找到候选人......

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


【解决方案1】:

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

根据name lookup的规则,

(强调我的)

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

对于这种情况,名称operator&lt;&lt; 在名称空间my(即其自身)的范围内找到,然后名称查找停止,不会检查全局范围,也不会检查全局operator&lt;&lt;考虑以下重载解决方案。

还有

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

很好,因为没有隐藏名字。

观察 2:如果命名空间 my { } 被删除,则不会发生错误。

这很好,因为这两个operator&lt;&lt; 放在同一个范围内,即全局命名空间。然后可以找到operator&lt;&lt;,然后在重载决议时考虑,最后选择合适的。

按照 cmets 的建议,您可以申请 using 将全局命名空间中的名称引入命名空间 my;那么operator&lt;&lt; 都会被找到,然后在重载决议中考虑。

【讨论】:

    【解决方案2】:

    namespace my 中定义的operator&lt;&lt; 可防止重载决议考虑您在全局命名空间中定义的operator&lt;&lt;。您只能在此处依赖 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);
    }
    
    }
    

    【讨论】:

    • 或更明确地说:::operator&lt;&lt;(std::cout, std::pair&lt;int, int&gt;{ 5, 4 });
    • 我更喜欢 using 解决方案,因为它仍然允许 ADL
    猜你喜欢
    • 2012-11-16
    • 1970-01-01
    • 2020-05-05
    • 2017-04-11
    • 2023-04-08
    • 2015-10-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多