操作员<< overload not selected for rvalue std::ostringstream and std::unique_ptr

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

我注意到 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

c++ c++17 operator-overloading unique-ptr ostringstream
1个回答
0
投票

仅当存在可以接受左值引用的有效运算符重载时,才可以使用将右值引用输出流的运算符重载。请参阅 cppreference 的描述(重点是我的):

调用适当的插入运算符,给定输出流对象的右值引用(相当于

os << value
)。 仅当表达式
os << value
格式正确且
Ostream
是公开且明确派生自
std::ios_base
的类类型时,此重载才会参与重载决策。

由于参数依赖查找规则,不考虑您的运算符重载。

os << value
找不到这个重载,所以不考虑右值引用重载。

在C++20中

std::unique_ptr
收到它自己的
operator<<
重载
,这个可以通过ADL找到,因此右值引用运算符是有效的并被选择。

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