gpt4 book ai didi

c++ - 使用 "no match"和 "cannot bind lvalue"重载 `operator<<` 时出现 `std::wostream` 和 `std::string` 错误

转载 作者:太空狗 更新时间:2023-10-29 21:16:02 26 4
gpt4 key购买 nike

我在重载时出错 std::wostream::operator<<()对于 std::string .这是说明我的问题的最小测试用例:

#include <string>
#include <sstream>

inline std::wostream &operator<<(std::wostream &os, const std::string &)
{
return os;
}

class FakeOstream{};

namespace mynamespace {

class FakeClasse1 {
friend inline FakeOstream &operator<<(FakeOstream &out, const FakeClasse1 &) {
return out;
}
};

class FakeClasse2 {
friend inline FakeOstream &operator<<(FakeOstream &out, const FakeClasse2 &) {
return out;
}
};

void test()
{
auto mystring = std::string{u8"mystring"};
std::wostringstream s;
s << mystring; // The errors occur here
}

} // namespace mynamespace

可以在这里编译和执行代码:http://cpp.sh/9emtv

正如您在这里看到的,operator<< 有一个过载与 std::wostreamstd::string .除了声明之外,这两个假类是空的一个operator<<FakeOstream和他们自己。 test()功能实例化一个 std::wostringstream给它一个std::string .假的假类和测试函数在命名空间中。

此代码在 cpp.sh 的 s << mystring; 行产生以下错误:

 In function 'void mynamespace::test()':
25:10: error: cannot bind 'std::basic_ostream<wchar_t>' lvalue to 'std::basic_ostream<wchar_t>&&'
In file included from /usr/include/c++/4.9/istream:39:0,
from /usr/include/c++/4.9/sstream:38,
from 2:
/usr/include/c++/4.9/ostream:602:5: note: initializing argument 1 of 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = wchar_t; _Traits = std::char_traits<wchar_t>; _Tp = std::basic_string<char>]'
operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
^

当直接使用 g++(来自 MSYS2 的 5.3.0 版)时,一个 no match error也是显示:

./tmpbug.cpp: In function 'void mynamespace::test()':
./tmpbug.cpp:25:7: error: no match for 'operator<<' (operand types are 'std::wostringstream {aka std::__cxx11::basic_ostringstream<wchar_t>}' and 'std::__cxx11::basic_string<char>')
s << mystring;
^
In file included from C:/Appli/msys64/mingw64/include/c++/5.3.0/istream:39:0,
from C:/Appli/msys64/mingw64/include/c++/5.3.0/sstream:38,
from ./tmpbug.cpp:2:
C:/Appli/msys64/mingw64/include/c++/5.3.0/ostream:628:5: note: candidate: std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = wchar_t; _Traits = std::char_traits<wchar_t>; _Tp = std::__cxx11::basic_string<char>] <near match>
operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
^
C:/Appli/msys64/mingw64/include/c++/5.3.0/ostream:628:5: note: conversion of argument 1 would be ill-formed:
./tmpbug.cpp:25:10: error: cannot bind 'std::basic_ostream<wchar_t>' lvalue to 'std::basic_ostream<wchar_t>&&'
s << mystring;
^
In file included from C:/Appli/msys64/mingw64/include/c++/5.3.0/istream:39:0,
from C:/Appli/msys64/mingw64/include/c++/5.3.0/sstream:38,
from ./tmpbug.cpp:2:

据我所知,示例的所有部分对于错误都是必要的出现。如果我注释掉命名空间、伪类或其中一个 operator<<在假类中,代码编译得很好。而且,如果我只需将其中一个假类或测试函数移动到命名空间之外,代码也可以正常编译。

此外,我尝试使用编译器在 clang 3.7 上编译这个示例来自 http://cppreference.com ,并且代码似乎可以毫无问题地编译。

我的代码有问题还是 GCC 错误?如果这是一个 GCC 错误,是有解决方法吗?

最佳答案

这是个坏主意:

inline std::wostream &operator<<(std::wostream &os, const std::string &)

因为您不应该在 std 中对两种类型重载运算符不依赖于您自己的(std 或内置)类型。做……效果不佳。而且,在我看来,不应该被允许。

无论如何,您可以通过简单地创建自己的命名空间 notstd 来生成符合规范的代码的相同问题。和自己的类型 notstd::string ,然后在全局根命名空间中定义

inline std::wostream &operator<<(std::wostream &os, const notstd::string &)
{
return os;
}

并得到相同的症状。所以这并不重要。


运算符首先通过非限定名称查找找到,然后通过参数相关查找找到。

因为我们没有 using语句,非限定名称查找首先在封闭的命名空间中查找。如果没有找到,则搜索包含它的 namespace (最终是文件/全局 namespace )。

然后 ADL 使用通过 ADL 或 Koenig 查找找到的运算符对其进行扩充——它在参数的 namespace 及其模板参数中查找。

现在,friend operator<<您定义确实在它们的类包含的命名空间中,但是它们通常很难找到。

不知何故,你对 friend operator<< 的双重声明正在让您的代码找到它们,并停止在全局命名空间中查找 << .

对我来说,这看起来像是一个错误。对于沼泽标准的非限定名称查找,这些“Koenig 运算符”中的任何一个都不应该是可见的,其类型与它们“包含”在其中的类无关。

MCVE :

#include <iostream>
#include <sstream>

namespace notstd {
struct string {};
}

inline void operator<<(std::wostream &os, const notstd::string &){ return; }

class FakeOstream{};

namespace mynamespace {

class UnusedClass1 {
friend inline void operator<<(FakeOstream &out, const UnusedClass1 &) { return; }
};

class UnusedClass2 {
// comment this line out and the code compiles:
friend inline void operator<<(FakeOstream &out, const UnusedClass2 &) { return; }
};

void test() {
auto mystring = notstd::string{};
std::wostringstream s;
s << mystring; // The errors occur here
}

} // namespace mynamespace

int main(){}

live example .

@T.C.发现似乎是这个错误正在修复:

test code

fix in gcc

关于c++ - 使用 "no match"和 "cannot bind lvalue"重载 `operator<<` 时出现 `std::wostream` 和 `std::string` 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36286448/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com