为啥我可以在临时 std::ofstream 对象上使用 `operator<<`?

Posted

技术标签:

【中文标题】为啥我可以在临时 std::ofstream 对象上使用 `operator<<`?【英文标题】:Why can I use `operator<<` on temporary std::ofstream objects?为什么我可以在临时 std::ofstream 对象上使用 `operator<<`? 【发布时间】:2019-09-10 09:21:50 【问题描述】:

根据 C++ 标准,您不能将临时对象绑定到非常量引用。由于流输出操作符被定义为

template <class CharT, class Traits, class Allocator>

std::basic_ostream<CharT, Traits>&
    operator<<(std::basic_ostream<CharT, Traits>& os,
               const std::basic_string<CharT, Traits, Allocator>& str);

我希望它不能在临时流对象上调用。但是,我尝试了以下并得到了意想不到的结果

#include <fstream>

std::ostream& print(std::ostream &stream) 
    stream << "test\n";
    return stream;


int main() 
    std::fstream("") << "test\n";
    // print(std::fstream("")); // Doesn't compile, as expected

这在 GCC 主干、Clang 主干和 MSVC 19 上编译。我什至在前两个上尝试了-pedantic-errors。虽然技术上可能这三个都错了,但我很可能误解了一些东西。

有人可以在标准中找到关于这是否是合法的 C++ 的明确答案吗?

【问题讨论】:

【参考方案1】:

存在通过右值引用获取流的重载:

template< class CharT, class Traits, class T >
basic_ostream< CharT, Traits >& operator<<( basic_ostream<CharT,Traits>&& os,
                                        const T& value );

temp 以os 传递。来自reference。

【讨论】:

【参考方案2】:

C++ 标准要求存在以下函数模板 (C++17 n4659 30.7.5.5 [ostream.rvalue]):

template <class charT, class traits, class T>
basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>&& os, const T& x);

效果指定为os &lt;&lt; x

请注意,提取 (&gt;&gt;) 也是如此。

【讨论】:

有趣。 this page 误导我假设没有 r 值参考版本。事实上,我什至验证了我发布的l值版本是在gcc和clang的程序集中调用的。显然是因为内联,但它加深了我的误解。 @patatahooligan 公平地说,确实没有针对std::basic_string 的右值版本,所以页面是正确的。不过,这个通用模板涵盖了所有类型。

以上是关于为啥我可以在临时 std::ofstream 对象上使用 `operator<<`?的主要内容,如果未能解决你的问题,请参考以下文章

std::ofstream,写入前检查文件是不是存在

std::ofstream::write 添加字符

如何将 std::ofstream& 传递给功能参数?

std::ofstream 无法在 win7/64 和 msvc2013 上使用 std::ios::ate 打开大文件

通过 SWIG 在 python 中使用 std::ifstream、std::ofstream 的技术?

fstream包含ofstream和ifstream的所有内容? [关闭]