Странное поведение с острингстримом
Я пытался придумать умный способ объединить различные вещи в один строковый аргумент для функции без необходимости использовать ostringstream
в явном виде. Я думал о:
#define OSS(...) \
dynamic_cast<std::ostringstream const&>(std::ostringstream() << __VA_ARGS__).str()
Однако, учитывая:
void f( string const &s ) {
cout << s << endl;
}
int main() {
char const *const s = "hello";
f( OSS( '{' << s << '}' ) );
ostringstream oss;
oss << '{' << s << '}';
cout << oss.str() << endl;
}
он печатает при запуске:
123hello}
{hello}
где 123 - код ASCII для }
, Почему использование макроса не так?
К вашему сведению: в настоящее время я использую g++ 4.2.1 на Mac OS X как часть Xcode 3.x.
Решение, которое я сейчас использую
class string_builder {
public:
template<typename T>
string_builder& operator,( T const &t ) {
oss_ << t;
return *this;
}
operator std::string() const {
return oss_.str();
}
private:
std::ostringstream oss_;
};
#define BUILD_STRING(...) (string_builder(), __VA_ARGS__)
using namespace std;
void f( string const &s ) {
cout << s << endl;
}
int main() {
char const *const s = "hello";
f( BUILD_STRING( '{', s, '}' ) );
}
2 ответа
Лучшее поточно-ориентированное решение без использования громоздкого макроса.
Исходный вызов функции таков:
f( OSS( '{' << s << '}' ) );
Как насчет, если вызов только это:
f(stringbuilder() << '{' << s << '}' );
где stringbuilder
реализован как:
struct stringbuilder
{
std::ostringstream ss;
template<typename T>
stringbuilder & operator << (const T &data)
{
ss << data;
return *this;
}
operator string() { return ss.str(); }
};
void f( string const &s ) {
cout << s << endl;
}
Тестовое задание:
int main() {
char const *const s = "hello";
f(stringbuilder() << '{' << s << '}' );
}
Выход:
{hello}
Демо онлайн: http://ideone.com/QHFf4
std::ostringstream()
является временным, который, таким образом, может быть связан только с константными ссылками. Автономный оператор<< (который принимает неконстантные ссылки в качестве первого аргумента) не учитывается, а только член-член. Лучшее совпадение для этих символов - преобразование их в int.
Эта проблема часто возникает со строковыми литералами, адрес которых затем отображается.
Чтобы решить проблему, трюк состоит в том, чтобы найти способ преобразовать временное в ссылку. Член operator<<
Это делается, но только тот, что для манипулятора, делает это без побочного эффекта и только в том случае, если манипулятор представляет собой noop - можно использовать сброс. Члены флеша и записи также являются кандидатами. Так, например,
#define OSS(...) \
dynamic_cast<std::ostringstream const&>(std::ostringstream().flush() << __VA_ARGS__).str()