my_macro << 1 << "hello world" << blah->getValue() << std::endl;
должен расшириться в:
std::ostringstream oss;
oss << 1 << "hello world" << blah->getValue() << std::endl;
ThreadSafeLogging(oss.str());
No. Проблема в том, что без использования синтаксиса функции макрос ограничивается заменой только там, где он есть.
Но если вы хотели использовать синтаксис функции, вы можете заменить материал как до, так и после аргументов.
my_macro(1 << "hello world" << blah->getValue() << std::endl);
Вы можете определить MyMacro как:
#define my_macro(args) std::ostreamstring oss; \
oss << args; \
ThreadSafeLogging(oss.str());
-121--2170220- Похоже, что viewForHeaseInSection вызывается раньше, чем «» ForHeaseInSection «». Однако если для определенной строки, в которой не требуется использовать представление, возвращается значение nil, вызывается startForHeireInSection.
-121--3390932-#define my_macro my_stream()
class my_stream: public std::ostringstream {
public:
my_stream() {}
~my_stream() {
ThreadSafeLogging(this->str());
}
};
int main() {
my_macro << 1 << "hello world" << std::endl;
}
Создается временный поток типа my _
, который является подклассом ostringstream
. Все операции с этой временной системой работают так же, как и в ostringstream
.
Когда оператор заканчивается (т.е. сразу после точки с запятой на всей операции печати в main ()) временный объект выходит из области действия и уничтожается. Деструктор my _ stream
вызывает ThreadSafeLogging
с ранее собранными данными.
Протестировано (г++).
Спасибо/кредит динго за указание на то, как упростить все это, поэтому мне не нужен перегруженный оператор < <
. Слишком плохие upvotes не могут быть общими.
Не могли бы вы просто унаследовать от ostream и предоставить свою собственную потокобезопасную реализацию? Тогда вы могли бы просто сделать
myCOutObject << 1 << "hello world" << blah->getValue() << std::endl;
И получить ту же функциональность без макросов и при правильном использовании C ++?
Взгляните на google-glog , они делают это с помощью временного объекта, созданного с помощью
LOG(INFO) << "log whatever" << 1;
, и у них также есть другие интересные макросы, такие как LOG_IF et al.
Нет. Проблема в том, что без использования синтаксиса функции макрос ограничивается заменой только там, где он есть.
Но если вы хотели использовать синтаксис функции, вы можете заменить вещи как до, так и после аргументов.
my_macro(1 << "hello world" << blah->getValue() << std::endl);
Вы можете определить MyMacro как:
#define my_macro(args) std::ostreamstring oss; \
oss << args; \
ThreadSafeLogging(oss.str());
Вот еще один неприятный трюк, который я видел где-то еще. У него есть существенный недостаток по сравнению с моим другим ответом: вы не можете использовать его дважды в одной и той же области, потому что он объявляет переменную. Тем не менее, это может быть интересно для других случаев, когда вы хотите, чтобы somemacro foo
запускал что-то после foo
.
#define my_macro \
std::ostringstream oss; \
for (int x=0; x<2; ++x) \
if (x==1) ThreadSafeLogging(oss.str()); \
else oss
int main() {
my_macro << 1 << "hello world" << std::endl;
}
Учитывая, что эти строки включены где-то в коде, да, возможно, макрос
#include <iostream>
#include <sstream>
__ LINE __
определяется всеми стандартными компиляторами. {{ 1}} Таким образом, мы можем использовать его для генерации имени переменной, которое меняется каждый раз, когда вы используете макрос:)
Вот новая версия, которая рассматривается только как инструкция с одним оператором: (EDITED )
#define Var_(Name, Index) Name##Index
#define Var(Name, Index) Var_(Name, Index)
#define my_macro \
for (struct { int x; std::ostringstream oss; } Var(s, __LINE__) = { 0 }; \
Var(s, __LINE__).x<2; ++Var(s, __LINE__).x) \
if (Var(s, __LINE__).x==1) ThreadSafeLogging(Var(s, __LINE__).oss.str()); \
else Var(s, __LINE__).oss
// So you can use it like this
int main()
{
if (4 != 2)
my_macro << 4 << " hello " << std::endl;
my_macro << 2 << " world !" << std::endl;
}
Разработчику, вероятно, не потребуется использовать этот макрос дважды в одной строке из-за простоты оператора <<
. Но если вам это нужно, вы можете переключить использование __ LINE __
на __ COUNTER __
(что нестандартно!). Спасибо Quuxplusone за этот совет