我注意到 std::basic_ostream 运算符<< overload for rvalue ostreams is not selected for a temporary std::ostringstream in combination with std::unique_ptr.
#include <iostream>
#include <memory>
#include <sstream>
std::ostream& operator<<(std::ostream& os, const std::unique_ptr<int>& /*res*/)
{
os << "Let's print something" << std::endl;
return os;
}
int main()
{
std::unique_ptr<int> res;
std::ostringstream {} << res;
return 0;
}
使用 GCC 14.2 和 C++17 编译的上述代码结果为
error: no match for 'operator<<' (operand types are 'std::ostringstream' {aka 'std::__cxx11::basic_ostringstream<char>'} and 'std::unique_ptr<int>')
很明显,不能直接选择用户定义的
operator<<
重载,因为它采用对 ostream 的非常量左值引用,而该 ostream 不能绑定到临时(右值)ostream。
我期望承受的超载是
template< class Ostream, class T >
Ostream&& operator<<( Ostream&& os, const T& value );
来自
std::basic_ostream
https://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt2
编译上面的代码时,GCC 对上述运算符输出以下错误
/opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/ostream:807:5: note: candidate: 'template<class _Ostream, class _Tp> _Ostream&& std::operator<<(_Ostream&&, const _Tp&)'
807 | operator<<(_Ostream&& __os, const _Tp& __x)
| ^~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/ostream:807:5: note: template argument deduction/substitution failed:
/opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/ostream: In substitution of 'template<class _Ostream, class _Tp> _Ostream&& std::operator<<(_Ostream&&, const _Tp&) [with _Ostream = std::__cxx11::basic_ostringstream<char>; _Tp = std::unique_ptr<int>]':
<source>:14:30: required from here
14 | std::ostringstream {} << res;
| ^~~
/opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/ostream:791:46: error: no match for 'operator<<' (operand types are 'std::__cxx11::basic_ostringstream<char>' and 'const std::unique_ptr<int>')
791 | = decltype(std::declval<_Os&>() << std::declval<const _Tp&>())>
| ~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
任何人都可以解释为什么
decltype(std::declval<_Os&>() << std::declval<const _Tp&>())
对于_Os = std::ostringstream
和_Tp = std::unique_ptr<int>
失败吗?
您可以在这里尝试一下:https://godbolt.org/z/vPqEeME8z
仅当存在可以接受左值引用的有效运算符重载时,才可以使用将右值引用输出流的运算符重载。请参阅 cppreference 的描述(重点是我的):
调用适当的插入运算符,给定输出流对象的右值引用(相当于
)。 仅当表达式os << value
格式正确且os << value
是公开且明确派生自Ostream
的类类型时,此重载才会参与重载决策。std::ios_base
由于参数依赖查找规则,不考虑您的运算符重载。
os << value
找不到这个重载,所以不考虑右值引用重载。
在C++20中
std::unique_ptr
收到它自己的operator<<
重载,这个可以通过ADL找到,因此右值引用运算符是有效的并被选择。