简体   繁体   English

为什么必须在 C++ 的“全局”scope 中声明 `std::ostream& operator<<` 覆盖?

[英]Why `std::ostream& operator<<` overriding must be declare in 'global' scope in C++?

Description描述

I'm overriding << operator for std::ostream to ease object display in my code.我正在重写std::ostream<< operator ,以简化 object 在我的代码中的显示。 I use differents namespaces where I define types of object to display.我使用不同的命名空间,在其中定义要显示的 object 类型。

That leads me to a compilation error.这导致我出现编译错误。 I have found a fix.我找到了解决办法。 It seems that overriding must be declare in a global scope but I really don't understand why.似乎必须在全局 scope 中声明覆盖,但我真的不明白为什么。 Can someone explain what cause the error?有人可以解释导致错误的原因吗?

Error错误

main.cpp:22:38: error: no match for ‘operator<<’ (operand types are ‘std::basic_ostream’ and ‘std::vector’)
         std::cout <<"printVector = " << data << std::endl;
         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~

Sample code (don't compile)示例代码(不要编译)

Here is a dummy exemple to show the error.这是一个显示错误的虚拟示例。

#include <iostream>
#include <vector>

inline std::ostream&
operator<<(std::ostream& strm, std::vector<uint8_t>& buffer)
{
    return strm << "display std::vector<uint8_t>";
}
    
namespace aNamespace {
    enum TestEnum { a, b, c };
    
    inline std::ostream&
    operator<<(std::ostream& strm, TestEnum& value)
    {
        return strm << "display TestEnum";
    }
  
    static void printVector () 
    {
        std::vector<uint8_t> data {1, 12, 56, 241, 128};
        std::cout <<"printVector = " << data << std::endl;
    }
}


int main()
{
    aNamespace::printVector();
    return 0;
}

Environnement环境

C++11; C++11; GCC; GCC; Linux Linux

Sample code fix ( edited )示例代码修复(已编辑

Here is a fix version of code for those who are interresed.这是一个修复版本的代码,供那些感兴趣的人使用。

#include <iostream>
#include <vector>

inline std::ostream&
operator<<(std::ostream& strm, std::vector<uint8_t>& buffer)
{
    return strm << "display std::vector<uint8_t>";
}

namespace aNamespace {
    using ::operator<<;

    enum class TestEnum { a, b, c };
    
    inline std::ostream&
    operator<<(std::ostream& strm, TestEnum value)
    {
        return strm << "display TestEnum";
    }

    static void printVector () 
    {
        std::vector<uint8_t> data {1, 12, 56, 241, 128};
        std::cout <<"printVector = " << data << std::endl;
    }
}

int main()
{
    aNamespace::printVector();
    return 0;
}

ADL strikes again ADL 再次来袭

For resolving operator overloads, C++ uses Argument Dependent Lookup .为了解决运算符重载, C++ 使用Argument Dependent Lookup In short, it will search the namespace of either parameter (in this case namespace std ) and the namespace of the call of the operator ( aNamespace ), going up the hierarchy if no operator overload is found .简而言之,它将搜索任一参数的命名空间(在本例中为命名空间std )和运算符调用的命名空间( aNamespace ),如果未找到运算符重载,则向上层级。

The namespace std does not contain any matching overload, but it contains other non-matching overloads, so parent namespace is not searched.命名空间std不包含任何匹配的重载,但它包含其他不匹配的重载,因此不搜索父命名空间。

Now, if namespace aNamespace does not contain any overload of operator << , parent namespace (global) is searched and correct overload is found, like in your "Sample code fix" example.现在,如果命名空间aNamespace不包含operator <<的任何重载,则会搜索父命名空间(全局)并找到正确的重载,就像在“示例代码修复”示例中一样。
However, if it contains any overload for operator << , even a non-matching one, lookup will not consider the parent namespace and the correct overload cannot be found.但是,如果它包含operator <<的任何重载,即使是不匹配的重载,查找也不会考虑父命名空间,并且无法找到正确的重载。

This is one of the reasons why some C++ gurus advocate against extensive use of namespaces, or at least to limit it to a single namespace per project (see for example this article by Titus Winters).这就是为什么一些 C++ 专家提倡反对广泛使用命名空间,或者至少将其限制为每个项目使用一个命名空间的原因之一(例如,参见 Titus Winters 的这篇文章)。


One possible fix is as you listed, but it may have problems itself, when compiler will look for overload using aNamespace::TestEnum .一种可能的修复方法是您列出的,但它本身可能有问题,当编译器将使用aNamespace::TestEnum查找重载时。 Prefer to have operator overload in the namespace which encapsulates one of the arguments.更喜欢在封装 arguments 之一的命名空间中具有运算符重载。

Better solution would be to explicitly add operators from global scope to your namespace scope or function scope:更好的解决方案是将全局 scope 中的运算符显式添加到您的命名空间 scope 或 function Z31A1FD140BE4BEF2D5ZA18A:2

 using ::operator<<;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 重载&lt;&lt;在C ++中的运算符-为什么返回类型是引用std :: ostream& - Overloading the << operator in C++ -why return type is a reference std::ostream& “覆盖” ostream&运算符&lt; - “Overriding” ostream& operator << “对&#39;std::operator&lt;&lt;(std::ostream&amp;, std::LinkedList const&amp;)的未定义引用”C++ - "Undefined reference to 'std::operator<<(std::ostream&, std::LinkedList const&)" C++ &#39;运算符&lt;&lt;(std :: ostream&,int&)&#39;不明确 - 'operator<<(std::ostream&, int&)’ is ambiguous std :: ostream&运算符&lt;&lt;类型推导 - std::ostream& operator<< type deduction 为什么编译器现在接受从 std::stringstream::operator&lt;&lt;() 返回的 std::ostream&amp; 上调用 str() 成员? - Why do compilers now accept to call str() member on a returned std::ostream& from std::stringstream::operator<<()? “friend std::ostream&amp; operator&lt;&lt;(std::ostream&amp; out, LinkedList&amp; list)”是什么意思? - What does “friend std::ostream& operator<<(std::ostream& out, LinkedList& list)” mean? std :: ostream&运算符&lt;&lt;(std :: ostream&sstr,const T&val)的模棱两可的重载 - Ambiguous overload of std::ostream& operator<<(std::ostream& sstr, const T& val) std::ostream&amp; operator&lt;&lt;(std::ostream&amp;, const T&amp;) 未被覆盖 - std::ostream& operator<<(std::ostream&, const T&) not being overridden 为什么C ++运算符重载必须包含“ ostream&os”? - Why the “ostream & os” must be there for C++ operator overload?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM