为什么编译器无法为我的运算符推断出 std::endl 的类型<<(T&&)?

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

我正在使用完美转发将类型通过管道传输到关联的

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 的类型,因为它是预先确定的,还是我遗漏了一些重要的东西?

c++ operator-overloading perfect-forwarding forwarding-reference
1个回答
1
投票

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;
}
© www.soinside.com 2019 - 2024. All rights reserved.