У меня есть класс, производный от std :: ostringstream и кодирующий понравившийся оператор потокового вывода << friend-func, так что у меня есть возможность предварительно обработать что-то до того, как произойдет реальный потоковый вывод. Но если второй операнд << является объектом std :: map (или unordered_map), мои коды не могут пройти компиляцию с GCC, в то время как второй операнд, который имеет много других типов, может быть принят. Я пробовал int, string, c-string, vector и т.д ... и все они в порядке, но map и unordered_map. </p>
Вот минимальный воспроизводимый пример:
#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<<
(типы операндов std::basic_ostream<char>
и const std::unordered_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >
)
Как указывает @nm, это выглядит как «Невозможно связать ссылку lvalue с временным объектом».
Но почему это можно сделать, когда второй операнд другого типа? типы, такие как 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;
};
Поскольку еще одна причина , я действительнонужен регистратор, чтобы быть временным. Кто-нибудь, пожалуйста, дайте мне решение? Любые намеки будут оценены!