【问题标题】:Why can not I overload operator<< with ostream and map( or unordered_map)?为什么我不能用 ostream 和 map(或 unordered_map)重载 operator<<?
【发布时间】:2019-09-30 02:00:02
【问题描述】:

我有一个派生自 std::ostringstream 的类,并编写了一个喜欢流输出的操作符

这是一个最小的可重现示例:

#include <iomanip>
#include <iostream>
#include <map>
#include <ostream>
#include <sstream>
#include <string_view>
#include <vector>
#include <unordered_map>

using namespace std;

enum class LogLevel { Debug, Infor, Notif, Warnn, Error, Fatal };
constexpr string_view LevelNames[] { "Debug", "Infor", "Notif", "Warnn", "Error", "Fatal" };
LogLevel sysLogLevel { LogLevel::Debug };

class Logger : public ostringstream {
public:
   Logger( LogLevel lv ) : logLevel( lv ) {};

   ~Logger() override {
      cout << LevelNames[static_cast<int>( logLevel )] << ':' << str() << '\n';
   };

   LogLevel logLevel;
};

template <typename T>
inline Logger& operator<<( Logger& lg, const T& body ) {
   if ( lg.logLevel >= sysLogLevel )
      static_cast<std::ostream&>( lg ) << body;
   return lg;
};

using StrStrMap = map<string, string>;
inline ostream& operator<<( ostream& os, const StrStrMap& ssm ) {
   os << '{';
   for ( const auto& [k,v] : ssm )
      os << k << ':' << v << ',';
   os << '}';
   return os;
};

int main() {
   StrStrMap ssm1 { { "Flower", "Red" }, { "Grass", "Green" } };

   cout << ssm1 << endl;                              // OK!

   { Logger log { LogLevel::Fatal }; log << ssum1; }  // OK!

   Logger(LogLevel::Infor) << ssm1;                   // Compiling Error!

   return EXIT_SUCCESS;
};

GCC的错误信息是:

/usr/include/c++/8/ostream:656:11: 错误:operator&lt;&lt; 不匹配(操作数类型为std::basic_ostream&lt;char&gt;const std::unordered_map&lt;std::__cxx11::basic_string&lt;char&gt;, std::__cxx11::basic_string&lt;char&gt; &gt;

正如@n.m 指出的那样。 ,看起来像“无法将左值引用绑定到临时 obj”。

但是为什么第二个操作数是其他类型如int、string、c-string、vector等时可以做到呢?

这是我对其他类型的尝试:

template<typename T>
class MyIntTemplate {
public:
   MyIntTemplate( T p ) : payLoad(p) {};
   T payLoad;
};
using MyInt = MyIntTemplate<int>;
inline ostream& operator<<( ostream& os, const MyInt& mi ) {
   os << mi.payLoad;
   return os;
};

using StrVec = vector<string>;
inline ostream& operator<<( ostream& os, const StrVec& sv ) {
   os << '{';
   for ( const auto& v : sv )
      os << v << ',';
   os << '}';
   return os;
};

int main() {
   Logger(LogLevel::Infor) << MyInt(123);                   // OK!
   Logger(LogLevel::Warnn) << 456;                          // OK!
   Logger(LogLevel::Debug) << "a Debugging Log";            // OK!
   Logger(LogLevel::Infor) << string( "a Informing Log" );  // OK!

   StrVec sv1 { "Flower", "Grass" };
   Logger(LogLevel::Fatal) << sv1;                          // OK!

   return EXIT_SUCCESS;
};

因为another reason,我真的需要临时记录器。 有人能给我一个解决方案吗? 任何提示将不胜感激!

【问题讨论】:

  • 不应该是inline Logger&amp; operator&lt;&lt;( Logger&amp; os, const StrStrMap&amp; ssm ) {...}吗?另外,这是一项学术活动吗?否则,重新实现现有功能通常是个坏主意。
  • 这条语句可以编译。 '记录器
  • 请发minimal reproducible example,不清楚你的代码哪些可以编译,哪些不能。
  • @n.m.我发布了一个示例作为答案
  • 不要发布任何不是答案的内容作为答案。 edit 你的问题。

标签: c++ operator-overloading iostream unordered-map stdmap


【解决方案1】:

Logger(LogLevel::Warnn) 是临时的。非常量引用不能绑定到临时对象。

inline ostream& operator<<( ostream& os,
//                          -------- <------ nope

【讨论】:

  • 谢谢@n.m。 !你是对的,看起来我们不能将左值引用绑定到临时 obj。但我真的需要记录器是临时的!你能给我一些提示吗?
【解决方案2】:

做 IOStreams 的工作并为右值创建一个包罗万象的重载:

template<class T>
Logger& operator<<(Logger&& lg, T const& x) {
  return lg << x;
}

【讨论】:

    猜你喜欢
    • 2012-01-17
    • 1970-01-01
    • 2011-07-18
    • 1970-01-01
    • 2018-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多