繁体   English   中英

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

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

描述

我正在重写std::ostream<< operator ,以简化 object 在我的代码中的显示。 我使用不同的命名空间,在其中定义要显示的 object 类型。

这导致我出现编译错误。 我找到了解决办法。 似乎必须在全局 scope 中声明覆盖,但我真的不明白为什么。 有人可以解释导致错误的原因吗?

错误

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

示例代码(不要编译)

这是一个显示错误的虚拟示例。

#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;
}

环境

C++11; GCC; Linux

示例代码修复(已编辑

这是一个修复版本的代码,供那些感兴趣的人使用。

#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 再次来袭

为了解决运算符重载, C++ 使用Argument Dependent Lookup 简而言之,它将搜索任一参数的命名空间(在本例中为命名空间std )和运算符调用的命名空间( aNamespace ),如果未找到运算符重载,则向上层级。

命名空间std不包含任何匹配的重载,但它包含其他不匹配的重载,因此不搜索父命名空间。

现在,如果命名空间aNamespace不包含operator <<的任何重载,则会搜索父命名空间(全局)并找到正确的重载,就像在“示例代码修复”示例中一样。
但是,如果它包含operator <<的任何重载,即使是不匹配的重载,查找也不会考虑父命名空间,并且无法找到正确的重载。

这就是为什么一些 C++ 专家提倡反对广泛使用命名空间,或者至少将其限制为每个项目使用一个命名空间的原因之一(例如,参见 Titus Winters 的这篇文章)。


一种可能的修复方法是您列出的,但它本身可能有问题,当编译器将使用aNamespace::TestEnum查找重载时。 更喜欢在封装 arguments 之一的命名空间中具有运算符重载。

更好的解决方案是将全局 scope 中的运算符显式添加到您的命名空间 scope 或 function Z31A1FD140BE4BEF2D5ZA18A:2

 using ::operator<<;

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM