Вы уже все в значительной степени закрепили это. Но это - немного оспаривания для следования. Таким образом позвольте мне попробовать суммировать то, что Вы сказали...
<час>, Что трудности здесь состоят в том что:
Мы играем с временным файлом ostringstream
объект, так взятие обращается, служится противопоказанием.
, поскольку это - временный файл, мы не можем тривиально преобразовать в ostream
объект через кастинг.
И конструктор [очевидно], и str()
является методами класса ostringstream
. (Да, мы должны использовать .str()
. Используя эти ostringstream
объект непосредственно завершил бы вызов ios::operator void*()
, возвратив подобное указателю хорошее/плохое значение и не строковый объект.)
operator<<(...)
существует и как наследованный ostream
методы и как глобальные функции. Во всех случаях это возвращается ostream&
ссылка.
выбором здесь для [1 111] является унаследованный метод ostream::operator<<(void* )
и глобальная функция operator<<(ostream&,const char* )
. Наследованный ostream::operator<<(void* )
побеждает, потому что мы не можем преобразовать в ostream
ссылка на объект для вызова глобальной функции. [Благодарность [1 149] coppro!]
Так, для осуществления этого мы должны:
ostringstream
. ostream
. ostringstream
. str()
. Выделение: ostringstream()
.
Преобразование: существует несколько вариантов. Другие предложили:
ostringstream() << std::string() // Kudos to *David Norman*
ostringstream() << std::dec // Kudos to *cadabra*
Или мы могли использовать:
ostringstream() . seekp( 0, ios_base::cur )
ostringstream() . write( "", 0 )
ostringstream() . flush()
ostringstream() << flush
ostringstream() << nounitbuf
ostringstream() << unitbuf
ostringstream() << noshowpos
#include <iomanip>
] Ссылка: См. , "Вставляют данные с форматом" 1/3 пути вниз на этой веб-странице. Мы не можем использовать:
operator<<( ostringstream(), "" )
забастовка> (ostream &) ostringstream()
забастовка> Добавление: Простой теперь.
Преобразование назад: Мы могли просто использовать (ostringstream&)
. Но dynamic_cast
было бы более безопасным. В маловероятном случае dynamic_cast
возвратился NULL
(это не было должно), следующий .str()
инициирует coredump.
Вызов str()
: Предположение.
Соединение всего этого.
#define FORMAT(ITEMS) \
( ( dynamic_cast<ostringstream &> ( \
ostringstream() . seekp( 0, ios_base::cur ) << ITEMS ) \
) . str() )
<час> Ссылки:
ostringstream
ostream::operator<<()
.
Вот то, что я использую. Все это вписывается в одно опрятное определение класса в заголовочном файле.
обновление: основное улучшение кода благодаря litb.
// makestring.h:
class MakeString
{
public:
std::stringstream stream;
operator std::string() const { return stream.str(); }
template<class T>
MakeString& operator<<(T const& VAR) { stream << VAR; return *this; }
};
Вот то, как это используется:
string myString = MakeString() << a << "b" << c << d;
Вот ответ как cadabra's, который не смешивает с состоянием ostream:
#define FORMAT(items) static_cast<std::ostringstream &>((std::ostringstream() << std::string() << items)).str()
я полагаю, что первый абзац ответа coppro описывает, почему вещи ведут себя этот путь.
Когда я взял решение mrree (тот, отмеченный "предпочтенный", тот, красиво объясненный и тот, работающий отлично на G ++), я столкнулся с проблемами с MSVC ++: Все строки, созданные с этим макросом, закончились пустые.
Часы (и большое царапание моей головы и выяснение "перезагрузил" вопрос здесь) позже, я узнал, что seekp () вызов был преступником. Я не уверен, что MSVC ++ делает по-другому с этим, но заменой
ostringstream().seekp( 0, ios_base::cur )
с cadabra's
ostringstream() << std::dec
работы для MSVC ++, также.
Проблема, которую Вы имеете, связана с тем, которое operator << (ostream&, char*)
не член ostream, и Ваш временный ostream экземпляр не может связать с не - const
ссылка. Вместо этого это выбирает void*
перегрузка, которая является членом ostream и таким образом не имеет того ограничения.
лучшее (но не самый легкий или самый изящный, любым фрагментом воображения!) должен был бы использовать Препроцессор Повышения для генерации большого количества функциональных перегрузок, каждый шаблонный на большом количестве объектов (включает, были опущены и принятие using namespace std;
):
#define MAKE_OUTPUT(z, n, data) \
BOOST_PP_TUPLE_ELEM(2, 0, data) << BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(2, 1, data), n);
#define MAKE_FORMAT(z, n, data) \
template <BOOST_PP_ENUM_PARAMS_Z(z, BOOST_PP_INC(n), typename T)> \
inline string format(BOOST_PP_ENUM_BINARY_PARAMS_Z(z, BOOST_PP_INC(n), T, p)) \
{ \
ostringstream s; \
BOOST_PP_REPEAT_##z(z, n, MAKE_OUTPUT, (s, p)); \
return s.str(); \
}
Это, как гарантируют, не будет работать точно (записал это, не тестируя), но это - в основном идея. Вы затем звоните BOOST_PP_REPEAT(N, MAKE_FORMAT, ())
для создания ряда взятия функций до параметров N, которые отформатируют строку, как Вы хотите к (замените N предпочтительным целым числом. Более высокие значения могут негативно влиять на время компиляции). Это должно быть достаточным, пока Вы не получаете компилятор с шаблонами variadic. Необходимо прочитать документацию препроцессора повышения, она имеет очень мощные функции для вещей как это. (Вы можете впоследствии #undef
макросы после вызова BOOST_PP_REPEAT
вызов для генерации функций)
Вот рабочее решение:
#define FORMAT(items) \
((std::ostringstream&)(std::ostringstream() << std::dec << items)).str()
я не вполне понимаю поведения первого аргумента.