调用operator时编译错误<< on a custom type from a different namespace

问题描述 投票:0回答:1

我在嵌套命名空间 (

abc::util
) 中有一个类型及其重载
operator<<
。但是,尝试从外部命名空间 (
abc
) 调用它会导致编译错误:

<source>: In function 'void abc::func(std::ostringstream&, const Foo&)':
<source>:38:9: error: no match for 'operator<<' (operand types are 'std::basic_ostream<char>' and 'const abc::Foo::MyType' {aka 'const abc::util::MyType'})
   37 |     oss << ';'
      |     ~~~~~~~~~~
      |         |
      |         std::basic_ostream<char>
   38 |         << foo.value;
      |         ^~ ~~~~~~~~~
      |                |
      |                const abc::Foo::MyType {aka const abc::util::MyType}

这是最小的例子:

#include <sstream>
#include <string>
#include <print>


namespace abc::util
{

struct MyType
{
    std::string value;
};

std::ostringstream&
operator<<( std::ostringstream& oss, const MyType& some_value )
{
    oss << some_value.value;
    return oss;
}

}

namespace abc
{

struct Foo
{
    using MyType = util::MyType;

    MyType value { "12345" };
};

void
func( std::ostringstream& oss, const Foo& foo )
{
    oss << ';'
        << foo.value; // does not compile
    
    // oss << ';';
    // oss << foo.value; compiles fine
}

}

int main( )
{
    std::ostringstream oss;
    abc::func( oss, abc::Foo { } );
    std::println( "{}", oss.view( ) );
}

我不太清楚为什么会这样编译:

    oss << ';';
    oss << foo.value;

但这不是:

    oss << ';'
        << foo.value;

有什么理由吗?

c++ namespaces operator-overloading argument-dependent-lookup
1个回答
0
投票

问题:

oss << ';'
返回
ostream&
而不是
ostringstream&
,因此您在尝试使用以下命令时无法链接调用:

oss << ';' << foo.value;

请注意,命名空间与此问题无关。

解决方案:

一个有效的解决方案是将您的

operator<<
func
更改为使用
std::ostream
而不是
std::ostringstream

即:
变化:

std::ostringstream& operator<<( std::ostringstream& oss, const MyType& some_value)

致:

std::ostream& operator<<( std::ostream& oss, const MyType& some_value)

并改变:

void func(std::ostringstream& oss, const Foo& foo)

致:

void func(std::ostream& oss, const Foo& foo)

请注意,您仍然可以将

main()
中的这些函数与
std::ostringstream oss
一起使用,因为
ostringstream
源自
ostream
。 因此这个解决方案只会让你的代码更加通用。

最后一点:

您在评论中提到,您不需要使用

std::cout
std::ofstream
之类的东西使这些类型可打印,但我不明白为什么这是反对此解决方案的论据:
让你的代码更通用是通常是一件积极的事情。
您不需要它(目前甚至永远)的事实并不会改变这一点。
在这种特定情况下,更通用的实现非常容易实现。
当然,可能有特定的原因来避免笼统(这就是为什么我写“通常”),但你没有具体说明。

© www.soinside.com 2019 - 2024. All rights reserved.