Я пытаюсь создать тонкую оболочку для экземпляра ostringstream, которая делегирует все операции вставки вложенному экземпляру ostringstream. Идея состоит в том, чтобы сохранить тип
при выполнении каскадных операций вставки. Обычно результирующий тип операции каскадной вставки является ostream&и любой оригинальный тип теряется. Я хотел бы сохранить тип выражения, потому что я хочу иметь возможность передать его методу для дальнейшей обработки и хотел бы иметь доступ к базовому потоку ostring для получения вставленных строковых данных.
Я хотел бы иметь возможность сделать что-то вроде следующего, и иметь результат выражения быть LgStream:
LgStream() << 26 << " a plain string " << std::string("a std string") << someObjWithItsOwnInsertionOperator;
Итак, я определил оператор<<() для базовых типов и шаблонных методов как универсальное средство для всего остального:
class LgStream
{
public:
ostringstream m_oss;
string str() {return m_oss.str();}
LgStream &operator<<(int x) {m_oss << x; return *this;}
LgStream &operator<<(long x) {m_oss << x; return *this;}
LgStream &operator<<(char x) {m_oss << x; return *this;}
LgStream &operator<<(bool x) {m_oss << (x ? 'T':'F'); return *this;}
LgStream &operator<<(double x) {m_oss << x; return *this;}
template <typename T>
LgStream &operator<<(const T &x) {m_oss << x; return *this;}
template <typename T>
LgStream &operator<<(const T x) {m_oss << x; return *this;}
};
У меня нет прав, и я получаю ошибки «неоднозначной перегрузки». Например:
LgStream() << "This is a plain string";
error: ambiguous overload for 'operator<<' in 'LgStream() << "This is a plain string"'
note: candidates are:
note: LgStream& LgStream::operator<<(int) <near match>
note: no known conversion for argument 1 from 'const char [23]' to 'int'
note: LgStream& LgStream::operator<<(long int) <near match>
note: no known conversion for argument 1 from 'const char [23]' to 'long int'
note: LgStream& LgStream::operator<<(char) <near match>
note: no known conversion for argument 1 from 'const char [23]' to 'char'
note: LgStream& LgStream::operator<<(bool)
note: LgStream& LgStream::operator<<(std::string)
note: LgStream& LgStream::operator<<(const T&) [with T = char [23], LgStream = LgStream]
note: LgStream& LgStream::operator<<(T) [with T = const char*, LgStream = LgStream]
Любая помощь оценена либо с синтаксисом, либо с неправильным подходом.
Почему бы вам не извлечь свой класс из std :: basic_ostringstream? Таким образом, вам не нужно определять свои собственные операторы вставки и вы можете использовать все стандартные операторы вставки.
В справочниках будет сказано, что извлекать уроки из STL опасно, и этого лучше избегать. AFAIK, это только проблема, если вы собираетесь использовать производный класс полиморфно, ссылаясь на его базовый класс. Для объяснения, поскольку ни один из классов STL не объявляет свои dtors виртуальными, уничтожение полиморфного указателя объекта не вызовет ваш производный класс dtor и может привести к утечке памяти. Пока вы не используете LgStream таким образом, вы должны быть в порядке.
Основной источник неоднозначности исходит от двух шаблонных функций. Делаешь «const T» &x «, а другой принимает» const T x «. Любое значение const T также будет соответствовать эталонной версии. Избавьтесь от одной из них. Я скомпилировал этот код в VC ++, после удаления определения для оператора»<<(const T x) «, и он скомпилирован без ошибок. Возможно, ваш компилятор сделает то же самое.