Наследование от ostringstream. В чем ошибка?
От: ZegSoft Россия  
Дата: 05.04.11 21:05
Оценка: 4 (1)
Здравствуйте.
Есть простенький код:
#include "stdafx.h"
#include <iostream>
#include <sstream>
#include <conio.h>
using namespace std;

class MyStream:public ostringstream
{
public:
    MyStream(){}
    ~MyStream()
    {
        cout<<str().c_str()<<endl;
    }
};

MyStream Prot()
{
    return MyStream();
}

int main()
{
    Prot()<<-1;
    Prot()<<5;
    Prot()<<5.5;
    Prot()<<'t';
    Prot()<<"Test";
    _getch();
    return 0;
}


Объясните пожалуйста, почему на выходе получается
То есть, строки и символы выводятся некорректно. В чем причина и как это можно исправить?
Re: Наследование от ostringstream. В чем ошибка?
От: Vamp Россия  
Дата: 05.04.11 21:16
Оценка:
ZS>Есть простенький код:
Я вообще не понимаю, как твой "простенький код" компилируется. У basic_streembuf (специализацией которого является ostringstream) конструктор копирования private, и копировать его нельзя.
Да здравствует мыло душистое и веревка пушистая.
Re: Наследование от ostringstream. В чем ошибка?
От: k.o. Россия  
Дата: 05.04.11 22:31
Оценка: 2 (1)
Здравствуйте, ZegSoft, Вы писали:

ZS>Здравствуйте.

ZS>Есть простенький код:

ZS>Объясните пожалуйста, почему на выходе получается

ZS> ZS>То есть, строки и символы выводятся некорректно. В чем причина и как это можно исправить?

Причина в том, что для строк и символов используется operator<< определённый как свободная функция, а для других тnипов — методы ostringstream. Свободные функции имеют сигнатуры вида
ostringstream & operator<<(ostringstream & stream, type value), поэтому они не могут использоваться для временных объектов, в результате вызываются методы для целых и указателей. Исправить можно, например, определив для MyStream соответствующие методы:
class MyStream
{
// ...
public:
using ostringstream::operator<<; // нужно, чтобы операторы MyStream не скрывали операторы ostringstream

MyStream & operator<<(char const * value)
{
    std::operator<<(*this, value);

    return *this;
}
//...
};
Re: Наследование от ostringstream. В чем ошибка?
От: andrey.desman  
Дата: 06.04.11 04:54
Оценка:
Здравствуйте, ZegSoft, Вы писали:

ZS>То есть, строки и символы выводятся некорректно. В чем причина и как это можно исправить?


Использую такую конструкцию (предложил ее не так давно по-моему remark)
class sfmt: boost::noncopyable
{
    std::ostringstream ss;

public:
    operator std::string () const { return ss.str(); }

    template<typename T>
    sfmt& operator << (T const& v)
    {
        ss << v;
        return *this;
    }
};


Допилить ее до нужного тебе поведения не проблема.
Re[2]: Наследование от ostringstream. В чем ошибка?
От: ZegSoft Россия  
Дата: 06.04.11 09:09
Оценка:
Здравствуйте, k.o., Вы писали:

KO>Здравствуйте, ZegSoft, Вы писали:


ZS>>Здравствуйте.

ZS>>Есть простенький код:

ZS>>Объясните пожалуйста, почему на выходе получается

ZS>> ZS>>То есть, строки и символы выводятся некорректно. В чем причина и как это можно исправить?

KO>Причина в том, что для строк и символов используется operator<< определённый как свободная функция, а для других тnипов — методы ostringstream. Свободные функции имеют сигнатуры вида

KO>ostringstream & operator<<(ostringstream & stream, type value), поэтому они не могут использоваться для временных объектов, в результате вызываются методы для целых и указателей. Исправить можно, например, определив для MyStream соответствующие методы:
KO>
KO>class MyStream
KO>{
KO>// ...
KO>public:
KO>using ostringstream::operator<<; // нужно, чтобы операторы MyStream не скрывали операторы ostringstream

KO>MyStream & operator<<(char const * value)
KO>{
KO>    std::operator<<(*this, value);

KO>    return *this;
KO>}
KO>//...
KO>};
KO>



Сегодня обнаружил удивительную особенность. Попробовал скомпилировать в VS2010 и вуаля: все работает как надо!!! А при компиляции в VS2008 вместо строк появляются цифры, как указано в примере. Почему такое различное поведение?
Re[2]: Наследование от ostringstream. В чем ошибка?
От: ZegSoft Россия  
Дата: 06.04.11 09:10
Оценка:
Здравствуйте, Vamp, Вы писали:

ZS>>Есть простенький код:

V>Я вообще не понимаю, как твой "простенький код" компилируется. У basic_streembuf (специализацией которого является ostringstream) конструктор копирования private, и копировать его нельзя.
А это вопрос уже к нашему любимому дядюшке биллу)) Во всех студиях компилится даже без предупреждений)
Re[2]: Наследование от ostringstream. В чем ошибка?
От: ZegSoft Россия  
Дата: 06.04.11 09:22
Оценка:
Здравствуйте, andrey.desman, Вы писали:

AD>Здравствуйте, ZegSoft, Вы писали:


ZS>>То есть, строки и символы выводятся некорректно. В чем причина и как это можно исправить?


AD>Использую такую конструкцию (предложил ее не так давно по-моему remark)

AD>
AD>class sfmt: boost::noncopyable
AD>{
AD>    std::ostringstream ss;

AD>public:
AD>    operator std::string () const { return ss.str(); }

AD>    template<typename T>
AD>    sfmt& operator << (T const& v)
AD>    {
AD>        ss << v;
AD>        return *this;
AD>    }
AD>};
AD>


AD>Допилить ее до нужного тебе поведения не проблема.


Первоначально я так и сделал. Но указанный пример не позволяет использовать функторы STL. То есть, например, если я напишу

sfmt()<<"Test"<<std::endl;


Компилятор будет ругаться.
Можно конечно переделать operator <<, чтобы он возвращал не sfmt&, а ostringstream&. В этом случае, указанный пример будет работать. Однако если поменять местами строку и endl
sfmt()<<std::endl<<"Test";


появятся все те же ошибки компиляции.
Следовательно, такой подход тоже не подходит, так как иногда бывает нужно настроить параметры форматирования через функторы STL (например точность вывода чисел с плавабщей запятой).
Кстати попробовал скомпилировать свой первоначальный пример в VS2010 — все работает как надо. А в VS2008 — вместо строк выводятся цифры. Почему такая разница??
Re: Наследование от ostringstream. В чем ошибка?
От: _nn_ www.nemerleweb.com
Дата: 06.04.11 09:28
Оценка:
Здравствуйте, ZegSoft, Вы писали:

ZS>То есть, строки и символы выводятся некорректно. В чем причина и как это можно исправить?


MyStream Prot()
{
    return MyStream();
}

Очевидно тут компилятор применил RVO и этот код соптимизировался.

Т.е. из
Prot()<<-1;

Мы получили
MyStream()<<-1;


Далее происходит следующее:
Для чисел вызывается встроенный метод.
Для строк имеется отдельная функция которая принимает stream&.
Ввиду того что у нас временный объект stringstream (MyStream) компилятор не может выбрать эту функцию.
Однако имеется встроенный метод , принимающий void*, вот его компилятор и выбирает. Что мы и видим.

Резюмирая это все, в VC есть баг.
Невзирая на невозможность создания конструктора копирования мы имеем возможность "копировать" объект.

Кстати, при /Wall можно получить предупреждение о том, что невозможно сгенерировать конструктор копирования.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[3]: Наследование от ostringstream. В чем ошибка?
От: k.o. Россия  
Дата: 06.04.11 09:48
Оценка: 2 (1)
Здравствуйте, ZegSoft, Вы писали:

ZS>Здравствуйте, k.o., Вы писали:


KO>>Здравствуйте, ZegSoft, Вы писали:


ZS>>>Здравствуйте.

ZS>>>Есть простенький код:

ZS>Сегодня обнаружил удивительную особенность. Попробовал скомпилировать в VS2010 и вуаля: все работает как надо!!! А при компиляции в VS2008 вместо строк появляются цифры, как указано в примере. Почему такое различное поведение?


r-value references в VS2010 добавились перегрузки операторов << принимающие r-value reference на stream, что позволяет использовать их с временными объектами, поэтому там выбираются правильные операторы для символов и строк.
Re[4]: Наследование от ostringstream. В чем ошибка?
От: ZegSoft Россия  
Дата: 06.04.11 10:10
Оценка:
Здравствуйте, k.o., Вы писали:

KO>Здравствуйте, ZegSoft, Вы писали:


ZS>>Здравствуйте, k.o., Вы писали:


KO>>>Здравствуйте, ZegSoft, Вы писали:


ZS>>>>Здравствуйте.

ZS>>>>Есть простенький код:

ZS>>Сегодня обнаружил удивительную особенность. Попробовал скомпилировать в VS2010 и вуаля: все работает как надо!!! А при компиляции в VS2008 вместо строк появляются цифры, как указано в примере. Почему такое различное поведение?


KO>r-value references в VS2010 добавились перегрузки операторов << принимающие r-value reference на stream, что позволяет использовать их с временными объектами, поэтому там выбираются правильные операторы для символов и строк.


Ясно) Спасибо за разъяснения.
Объединив советы получился такой код (в Ващем примере не был перегружен оператор для char, соответственно отдельные символы выводились цифрами. чтобы не копировать код, решил сделать оператор шаблонным).

class MyStream:public ostringstream
{
public:
    MyStream(){}
    ~MyStream()
    {
        cout<<str().c_str()<<endl;
    }
    using ostringstream::operator<<; // нужно, чтобы операторы MyStream не скрывали операторы ostringstream

    template<typename T>
    MyStream & operator<<(T value)
    {
        std::operator<<(*this, value);
        return *this;
    }

};


Кстати, тут многие пишут, что этот код не валидный и компилится исключительно из-за багов в MSVS. Каково Ваше мнение по этому поводу?
Re[5]: Наследование от ostringstream. В чем ошибка?
От: k.o. Россия  
Дата: 06.04.11 10:25
Оценка: 1 (1)
Здравствуйте, ZegSoft, Вы писали:

ZS>Кстати, тут многие пишут, что этот код не валидный и компилится исключительно из-за багов в MSVS. Каково Ваше мнение по этому поводу?


Полностью с ними согласен.
Re[3]: Наследование от ostringstream. В чем ошибка?
От: blackhearted Украина  
Дата: 06.04.11 10:27
Оценка:
Здравствуйте, ZegSoft, Вы писали:

ZS>Здравствуйте, Vamp, Вы писали:


ZS>>>Есть простенький код:

V>>Я вообще не понимаю, как твой "простенький код" компилируется. У basic_streembuf (специализацией которого является ostringstream) конструктор копирования private, и копировать его нельзя.
ZS>А это вопрос уже к нашему любимому дядюшке биллу)) Во всех студиях компилится даже без предупреждений)

use codepad, Luke!
Re[5]: Наследование от ostringstream. В чем ошибка?
От: Centaur Россия  
Дата: 06.04.11 17:37
Оценка:
Здравствуйте, ZegSoft, Вы писали:

ZS>    template<typename T>
ZS>    MyStream & operator<<(T value)
ZS>    {
ZS>        std::operator<<(*this, value);
ZS>        return *this;
ZS>    }


Так неправильно делать, потому что правильный operator<< для конкретного T будет, скорее всего, не в std, а в том namespace, где определён T.
Re[3]: Наследование от ostringstream. В чем ошибка?
От: andrey.desman  
Дата: 06.04.11 19:37
Оценка: 9 (1)
Здравствуйте, ZegSoft, Вы писали:

ZS>Первоначально я так и сделал. Но указанный пример не позволяет использовать функторы STL.


Да, надо догружать операторы.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.