Intereting Posts
Как сделать расшифровку AES с помощью OpenSSL Откройте COM-порт на C ++ с номером выше, чем 9 boost :: spirit parser возвращает пустой вектор Как изменить поведение для всех экземпляров classа в classе только заголовка Счетчики производительности в c ++ без lodctr Проблемы с кодом ввода кода Использование объявления «не найдено» в драйвере mongodb c ++ Есть ли способ подавить сглаживание имени c ++? Разделение больших чисел в строках Попытка запуска скомпилированного исполняемого файла на целевом устройстве не выполняется: Нет такого файла или каталога Специализация шаблона не работает при связывании Как преобразовать QImage в opencv Mat почему статическая переменная статической функции не может использоваться при создании одноэлементного classа в c ++? ATL: Я хочу создать class, который я могу использовать в качестве параметра для метода в моем classе. Почему я не могу заставить это работать? Модульное возведение в степень для большого mod в C ++

временная проблема возврата streamа streamstream

Я создаю регистратор со следующими разделами:

// #define LOG(x) // for release mode #define LOG(x) log(x) log(const string& str); log(const ostream& str); 

С идеей сделать:

 LOG("Test"); LOG(string("Testing") + " 123"); stringstream s; LOG(s << "Testing" << 1 << "two" << 3); 

Все это работает по назначению, но когда я это делаю:

 LOG(stringstream() << "Testing" << 1 << "two" << 3); 

Это не работает:

 void log(const ostream& os) { std::streambuf* buf = os.rdbuf(); if( buf && typeid(*buf) == typeid(std::stringbuf) ) { const std::string& format = dynamic_cast(*buf).str(); cout << format << endl; } } 

приводит к «форматированию», содержащему ненужные данные вместо обычной правильной строки.

Я думаю, это связано с тем, что временный stream, возвращаемый << оператором, переживает строку, из которой он происходит.

Или я ошибаюсь?

(Почему строка () работает таким образом? Это потому, что она возвращает ссылку на себя? Я предполагаю, что да.)

Я бы очень хотел сделать это таким образом, поскольку я бы избавился от дополнительного распределения при входе в режим выпуска.

Любые указатели или трюки, чтобы сделать это таким образом, будут приветствоваться. В моем фактическом решении у меня много разных функций журнала, и они все сложнее, чем это. Поэтому я предпочел бы, чтобы это каким-то образом реализовано в вызывающем коде. (И не изменяя мой #define, если это возможно)

Чтобы дать представление, пример одной из моих реальных #defines:

 #define LOG_DEBUG_MSG(format, ...) \ LogMessage(DEBUG_TYPE, const char* filepos, sizeof( __QUOTE__( @__VA_ARGS__ )), \ format, __VA_ARGS__) 

который соответствует varargs printf-подобным функциям журнала с использованием char *, string () и ostream (), а также неваграфных функций с использованием строковых (), exception () и HRESULT.

Кажется, я вижу, что происходит. Это дает ожидаемый результат:

 log(std::stringstream() << 1 << "hello"); 

в то время как это не делает:

 log(std::stringstream() << "hello" << 1); 

(он записывает шестнадцатеричное число, за которым следует цифра «1»)

Несколько элементов для объяснения:

  • Значение r не может быть привязано к неконстантной ссылке
  • Это нормально, чтобы вызвать функции-члены на временной
  • std :: ostream имеет оператор-член << (void *)
  • std :: ostream имеет оператор-член << (int)
  • Для char * оператор не является членом, это оператор << (std :: ostream &, const char *)

В приведенном выше коде std :: stringstream () создает временную (rvalue). Его время жизни не является проблематичным, так как оно должно продолжаться для всего полного выражения, которое оно объявлено (т. Е. До возврата вызова log ()).

В первом примере все работает нормально, потому что сначала вызывается оператор-член << (int), а затем возвращаемая ссылка может быть передана оператору << (ostream &, const char *)

Во втором примере оператор << (не может быть вызван с «std :: stringstream ()» в качестве 1-го аргумента, так как это потребует от него привязки к неконстантной ссылке. Однако оператор-член << (void *) в порядке, так как он является членом.

Кстати: почему бы не определить функцию log () как:

 void log(const std::ostream& os) { std::cout << os.rdbuf() << std::endl; } 

Измените макрос LOG() следующим образом:

 #define LOG(x) do { std::stringstream s; s << x; log(s.str()); } while(0) 

Это позволит использовать следующий синтаксис в ваших журналах отладки, поэтому вам не нужно вручную создавать stream строк.

 LOG("Testing" << 1 << "two" << 3); 

Затем определите его ни для чего для выпуска, и у вас не будет дополнительных ассигнований.