为什么编译器现在接受从 std::stringstream::operator<<() 对返回的 std::ostream& 调用 str() 成员?

Why do compilers now accept to call str() member on a returned std::ostream& from std::stringstream::operator<<()?

提问人:Fareanor 提问时间:9/19/2022 最后编辑:Peter MortensenFareanor 更新时间:1/26/2023 访问量:2056

问:

请考虑以下行:

std::string s = (std::stringstream() << "foo").str();

这不应该编译,因为被继承并返回一个没有成员。std::stringstream::operator<<()std::ostreamstd::ostream&str()

似乎主要编译器现在正在接受过去没有的代码。发生了什么标准更改来编译它?

我用 GCCClangMSVC 做了一些测试,我可以找到发生更改的版本:

编译器 拒绝时间(版本) 接受自(版本)
海湾合作委员会 11.1 11.2
12.0.1 13.0.0
MSVC公司 19.14 版 19.15 版

你可以在这里找到测试

C++ 语言律师

评论

1赞 user12002570 9/19/2022
确实很奇怪的错误。
1赞 Adrian Mole 9/19/2022
请注意,它显示了 class std::basic_stringstream<char,struct std::char_traits<char>,class std::allocator<char> > 的类型,因此“bug”(如果就是这样的话)就在那里,而不是在成员的使用中。auto t = (std::stringstream() << "foo"); std::cout << typeid(t).name() << "\n";t.str()
0赞 463035818_is_not_an_ai 9/19/2022
fwiw在这里你可以看到类型发生了变化:godbolt.org/z/hE38cKTdj(std::stringstream() << "foo")

答:

45赞 3 revsmolbdnilo #1

它们几乎同时添加了右值重载(见此处)。

右值重载是在添加到 C++ 11 中引入的,并返回与其左侧操作数相同类型的流。

正如评论中所指出的,它似乎在整整十年后被添加到编译器中的原因是,它是追溯性地添加到 C++11 中的,而且是最近才添加到的,可能是在被批准包含在 C++20 之后。

我正在把它变成一个社区维基,以防有人有意愿和耐心去寻找追溯添加背后的原因并修改答案。

评论

1赞 Hans Olsson 9/20/2022
我阅读规范的方式是在 2018-05-25 之后在 C++ 11 中追溯引入的;这意味着他们都迟到了,添加了一个添加得很晚的功能。
0赞 molbdnilo 9/21/2022
@HansOlsson 这听起来很有道理。你介意我把它添加到答案中吗?
1赞 Karl Nicoll 9/21/2022
@hansolsson - 当你说在 C++11 中引入时,你的意思是在 C++20 中引入还是在 2018 年被添加到(被取代 3 次)C++11 规范中?
0赞 quetzalcoatl 9/21/2022
@KarlNicoll:Hans 强调“追溯性”,所以我把它理解为“是的,回到了过去,并添加到了旧规范中”。奇怪的事情,但有时会发生在非常重要的功能上。不过我不是汉斯,所以不是100%确定。
1赞 Karl Nicoll 9/21/2022
@quetzalcoatl - 是的,我想你是对的,它在 cppref 中被列为 c++11 功能。这样的功能被向后移植到这么久以前,但又需要很多年才能获得广泛的编译器支持,这似乎很疯狂。这似乎不值得付出努力!疯狂的东西。