我正在使用完美转发将类型通过管道传输到关联的
JsonRecord
对象。但是,当我想将其作为令牌转发给 std::endl
时,编译器无法推断出 std::ostringstream
的类型。这是失败的确切代码:
#include <string>
#include <iostream>
#include <sstream>
#include <memory>
struct JsonRecord
{
JsonRecord() = delete;
JsonRecord(JsonRecord&&) = default;
~JsonRecord()
{
std::cout << _ostr.str() << std::endl;
};
template <typename T>
auto operator<<(T&& entry) -> JsonRecord&
{
_ostr << std::forward<T>(entry);
return *this;
}
std::ostringstream _ostr;
};
struct Log
{
template <typename T>
auto operator<<(T&& entry) -> JsonRecord
{
auto record = JsonRecord{};
record << std::forward<T>(entry);
return record;
};
};
int main()
{
Log mylog;
// This works
mylog << "hello";
// Then why doesn't this work?
mylog << "hello" << std::endl;
}
出现此错误消息:
<source>: In function 'int main()':
<source>:44:22: error: no match for 'operator<<' (operand types are 'JsonRecord' and '<unresolved overloaded function type>')
44 | mylog << "hello" << std::endl;
| ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~
<source>:17:10: note: candidate: 'template<class T> JsonRecord& JsonRecord::operator<<(T&&)'
17 | auto operator<<(T&& entry) -> JsonRecord&
| ^~~~~~~~
<source>:17:10: note: template argument deduction/substitution failed:
<source>:44:30: note: couldn't deduce template parameter 'T'
44 | mylog << "hello" << std::endl;
| ^~~~
In file included from /opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/bits/basic_string.h:48,
from /opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/string:55,
from <source>:1:
/opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/string_view:667:5: note: candidate: 'template<class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, std::basic_string_view<_CharT, _Traits>)'
667 | operator<<(basic_ostream<_CharT, _Traits>& __os,
| ^~~~~~~~
/opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/string_view:667:5: note: template argument deduction/substitution failed:
<source>:44:30: note: 'JsonRecord' is not derived from 'std::basic_ostream<_CharT, _Traits>'
44 | mylog << "hello" << std::endl;
| ^~~~
In file included from /opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/string:55,
from <source>:1:
/opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/bits/basic_string.h:6531:5: note: candidate: 'template<class _CharT, class _Traits, class _Alloc> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::__cxx11::basic_string<_CharT, _Traits, _Allocator>&)'
6531 | operator<<(basic_ostream<_CharT, _Traits>& __os,
| ^~~~~~~~
/opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/bits/basic_string.h:6531:5: note: template argument deduction/substitution failed:
<source>:44:30: note: 'JsonRecord' is not derived from 'std::basic_ostream<_CharT, _Traits>'
44 | mylog << "hello" << std::endl;
| ^~~~
In file included from /opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/bits/ios_base.h:46,
from /opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/ios:42,
from /opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/ostream:38,
from /opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/iostream:39,
from <source>:2:
/opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/system_error:279:5: note: candidate: 'template<class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::error_code&)'
279 | operator<<(basic_ostream<_CharT, _Traits>& __os, const error_code& __e)
| ^~~~~~~~
/opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/system_error:279:5: note: template argument deduction/substitution failed:
<source>:44:30: note: 'JsonRecord' is not derived from 'std::basic_ostream<_CharT, _Traits>'
44 | mylog << "hello" << std::endl;
| ^~~~
In file included from /opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/iostream:39,
from <source>:2:
/opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/ostream:513:5: note: candidate: 'template<class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, _CharT)'
513 | operator<<(basic_ostream<_CharT, _Traits>& __out, _CharT __c)
| ^~~~~~~~
/opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/ostream:513:5: note: template argument deduction/substitution failed:
<source>:44:30: note: 'JsonRecord' is not derived from 'std::basic_ostream<_CharT, _Traits>'
44 | mylog << "hello" << std::endl;
| ^~~~
In file included from /opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/iostream:39,
from <source>:2:
/opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/ostream:518:5: note: candidate: 'template<class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, char)'
518 | operator<<(basic_ostream<_CharT, _Traits>& __out, char __c)
| ^~~~~~~~
/opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/ostream:518:5: note: template argument deduction/substitution failed:
<source>:44:30: note: 'JsonRecord' is not derived from 'std::basic_ostream<_CharT, _Traits>'
44 | mylog << "hello" << std::endl;
| ^~~~
In file included from /opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/iostream:39,
from <source>:2:
/opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/ostream:524:5: note: candidate: 'template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, char)'
524 | operator<<(basic_ostream<char, _Traits>& __out, char __c)
| ^~~~~~~~
/opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/ostream:524:5: note: template argument deduction/substitution failed:
<source>:44:30: note: 'JsonRecord' is not derived from 'std::basic_ostream<char, _Traits>'
44 | mylog << "hello" << std::endl;
| ^~~~
In file included from /opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/iostream:39,
from <source>:2:
/opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/ostream:530:5: note: candidate: 'template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, signed char)'
530 | operator<<(basic_ostream<char, _Traits>& __out, signed char __c)
| ^~~~~~~~
/opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/ostream:530:5: note: template argument deduction/substitution failed:
<source>:44:30: note: 'JsonRecord' is not derived from 'std::basic_ostream<char, _Traits>'
44 | mylog << "hello" << std::endl;
| ^~~~
In file included from /opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/iostream:39,
from <source>:2:
/opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/ostream:535:5: note: candidate: 'template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, unsigned char)'
535 | operator<<(basic_ostream<char, _Traits>& __out, unsigned char __c)
| ^~~~~~~~
/opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/ostream:535:5: note: template argument deduction/substitution failed:
<source>:44:30: note: 'JsonRecord' is not derived from 'std::basic_ostream<char, _Traits>'
44 | mylog << "hello" << std::endl;
| ^~~~
In file included from /opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/iostream:39,
from <source>:2:
/opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/ostream:594:5: note: candidate: 'template<class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const _CharT*)'
594 | operator<<(basic_ostream<_CharT, _Traits>& __out, const _CharT* __s)
| ^~~~~~~~
/opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/ostream:594:5: note: template argument deduction/substitution failed:
<source>:44:30: note: 'JsonRecord' is not derived from 'std::basic_ostream<_CharT, _Traits>'
44 | mylog << "hello" << std::endl;
| ^~~~
In file included from /opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/ostream:829,
from /opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/iostream:39,
from <source>:2:
/opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/bits/ostream.tcc:321:5: note: candidate: 'template<class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const char*)'
321 | operator<<(basic_ostream<_CharT, _Traits>& __out, const char* __s)
| ^~~~~~~~
/opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/bits/ostream.tcc:321:5: note: template argument deduction/substitution failed:
<source>:44:30: note: 'JsonRecord' is not derived from 'std::basic_ostream<_CharT, _Traits>'
44 | mylog << "hello" << std::endl;
| ^~~~
In file included from /opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/iostream:39,
from <source>:2:
/opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/ostream:611:5: note: candidate: 'template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, const char*)'
611 | operator<<(basic_ostream<char, _Traits>& __out, const char* __s)
| ^~~~~~~~
/opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/ostream:611:5: note: template argument deduction/substitution failed:
<source>:44:30: note: 'JsonRecord' is not derived from 'std::basic_ostream<char, _Traits>'
44 | mylog << "hello" << std::endl;
| ^~~~
In file included from /opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/iostream:39,
from <source>:2:
/opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/ostream:624:5: note: candidate: 'template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, const signed char*)'
624 | operator<<(basic_ostream<char, _Traits>& __out, const signed char* __s)
| ^~~~~~~~
/opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/ostream:624:5: note: template argument deduction/substitution failed:
<source>:44:30: note: 'JsonRecord' is not derived from 'std::basic_ostream<char, _Traits>'
44 | mylog << "hello" << std::endl;
| ^~~~
In file included from /opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/iostream:39,
from <source>:2:
/opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/ostream:629:5: note: candidate: 'template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, const unsigned char*)'
629 | operator<<(basic_ostream<char, _Traits>& __out, const unsigned char* __s)
| ^~~~~~~~
/opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/ostream:629:5: note: template argument deduction/substitution failed:
<source>:44:30: note: 'JsonRecord' is not derived from 'std::basic_ostream<char, _Traits>'
44 | mylog << "hello" << std::endl;
| ^~~~
In file included from /opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/iostream:39,
from <source>:2:
/opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/ostream:750:5: note: candidate: 'template<class _Ostream, class _Tp> _Ostream&& std::operator<<(_Ostream&&, const _Tp&)'
750 | operator<<(_Ostream&& __os, const _Tp& __x)
| ^~~~~~~~
/opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/ostream:750:5: note: template argument deduction/substitution failed:
<source>:44:30: note: couldn't deduce template parameter '_Tp'
44 | mylog << "hello" << std::endl;
| ^~~~
In file included from /opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/memory:77,
from <source>:4:
/opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/bits/shared_ptr.h:70:5: note: candidate: 'template<class _Ch, class _Tr, class _Tp, __gnu_cxx::_Lock_policy _Lp> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::__shared_ptr<_Tp, _Lp>&)'
70 | operator<<(std::basic_ostream<_Ch, _Tr>& __os,
| ^~~~~~~~
/opt/compiler-explorer/gcc-11.4.0/include/c++/11.4.0/bits/shared_ptr.h:70:5: note: template argument deduction/substitution failed:
<source>:44:30: note: 'JsonRecord' is not derived from 'std::basic_ostream<_CharT, _Traits>'
44 | mylog << "hello" << std::endl;
| ^~~~
Compiler returned: 1
我的想法是编译器应该能够确定 std::endl 的类型,因为它是预先确定的,还是我遗漏了一些重要的东西?
std::endl
实际上是一个函数模板(像许多其他I/O操纵器一样)。operator<<
一起使用时,编译器不会推断其类型。
std::basic_ostream
有同样的问题,你可以类似地解决:
std::basic_ostream::operator<<
有特殊的重载(#18-20)来处理此类 I/O 操纵器:
basic_ostream& operator<<(
std::ios_base& (*func)(std::ios_base&) ); (18)
basic_ostream& operator<<(
std::basic_ios<CharT, Traits>& (*func)(std::basic_ios<CharT, Traits>&) ); (19)
basic_ostream& operator<<(
std::basic_ostream<CharT, Traits>& (*func)
(std::basic_ostream<CharT, Traits>&) ); (20)
他们的描述是:
18-20) 调用 func(*this)。这些重载用于实现输出 I/O 操纵器,例如 std::endl。
(重点是我的)
在您的情况下,将以下内容添加到
JsonRecord
(相当于上面的重载 18-20):
auto operator<<(std::ios_base& (*func)(std::ios_base&)) -> JsonRecord&
{
func(_ostr);
return *this;
}
auto operator<<(std::basic_ios<char>& (*func)(std::basic_ios<char>&)) -> JsonRecord&
{
func(_ostr);
return *this;
}
auto operator<<(std::basic_ostream<char>& (*func)(std::basic_ostream<char>&)) -> JsonRecord&
{
func(_ostr);
return *this;
}