ошибка C2027: использование неопределенного типа 'std :: basic_ostringstream <_Elem, _Traits, _Alloc>'
Вам нужно #include <sstream>
, чтобы получить [i/o]stringstream
классы.
О других ошибках
Проблема с перегрузкой формы
ostringstream& operator<<(ostringstream& stream, const mytype& a)
в том, что оно соответствует ostringstream
точно . Почему плохо иметь более точную перегрузку? Из стандарта, §13.3.3 / 1-2:
жизнеспособная функция F1 определяется как лучшая функция, чем другая жизнеспособная функция F2, если для всех аргументов i ICSi (F1) не хуже последовательности преобразования, чем ICSi (F2)…
Если существует ровно одна жизнеспособная функция, которая лучше, чем все другие жизнеспособные функции, то это
один выбранный по разрешению перегрузки; в противном случае вызов неверен
Поэтому, если operator<<( ostream &, int )
и operator<<( ostringstream &, mytype const & )
оба являются кандидатами на stream << value
, первое совпадение int
точно не имеет преобразования, а второе совпадение ostringstream
точно. Поэтому ни один не может быть «не хуже» для всех аргументов, и ни один из кандидатов не может быть выбран.
Но код является действительным из-за лазейки. Ваша перегрузка вообще не подходит, кроме случаев, когда вы фактически используете свой тип в вызове функции. Когда вы объявляете / определяете friend
внутри блока класса, он не вводит его ни в какую область имен; он просто связывает его с областью действия класса, что позволяет найти его, если этот тип класса описывает один из передаваемых аргументов.
В стандарте говорится об объявлениях друзей, хотя в другом разделе (14.6.5):
Объявления друзей не вводят новые имена ни в одну сферу ...
Итак, MSVC постарался быть милым и активно представил вашего друга окружающему пространству имен. Удар по MSVC.
Однако, когда я попытался добавить объявление, эквивалентное тому, что MSVC делал «бесплатно», Comeau и GCC приятно решили возникший конфликт перегрузки - нанес им удар. Либо это? Как оказалось, перегруженный вызов происходит в файле раньше, чем мое рекомендуемое объявление. Если я перенесу декларацию до class mytype {
(для чего требуется декларация форварда mytype
), то оба будут правильно жаловаться на неоднозначность.
Использование перегрузки до того, как она будет объявлена в области имен, представляется целесообразной в соответствии с §3.3-3.4 Стандарта. Так что на самом деле GCC и Comeau были правы. Точка декларации находится сразу после названия объявленного объекта. (И последнее, что я проверил, объявления самоссылочной функции могут по-прежнему вызывать сбой GCC .) ADL вызывает неквалифицированный поиск во вложенном пространстве имен в точке непосредственно перед включающим классом. (3.4.1 / 8, последний пункт, 3.4.1 / 9, 3.4.2 / 2a.) Если друг не был объявлен перед классом, он на законных основаниях не является кандидатом. (7.3.1.2/3) Разве C ++ не является красивым языком?
Как сохранить упрощенный пример в GCC, но нарушить последующий код.
friend ostringstream& operator<<(ostringstream& stream, const mytype& a) {
stream << (a.value);//compilation error
return stream;
}
};
ostringstream& operator<<(ostringstream& stream, const mytype& a); // <- here
После этого объявления невозможно будет записать int
в ostringstream
.
Как все равномерно разбить, с более простой семантикой объявления.
class mytype; // <- here
// and here:
inline ostringstream& operator<<(ostringstream& stream, const mytype& a);
class mytype {
public:
После этого объявления будет невозможно записать int
в ostringstream
… включая объявления друзей внутри class mytype {}
.
Фактическое решение.
Предполагается, что потоковые классы неразличимы. Если вы действительно хотите определить, подает ли данный поток строку в память (а вам не следует), лучше взглянуть на его внутренний объект streambuf
, возвращаемый rdbuf()
, который фактически выполняет ворчание ввода-вывода. Даже общий объект ostream
может иметь функциональность ostringstream
, если ему дано stringbuf
.
if ( typeid( stream.rdbuf() ) == typeid( stringbuf * ) ) {
// this is effectively a stringstream
} else {
// not a stringstream
}