Есть ли в любом случае, чтобы написать следующее в качестве C ++ Macro?

StackOverflow https://stackoverflow.com/questions/2196155

Вопрос

my_macro << 1 << "hello world" << blah->getValue() << std::endl;

следует расширить в:

std::ostringstream oss;
oss << 1 << "hello world" << blah->getValue() << std::endl;
ThreadSafeLogging(oss.str());
Это было полезно?

Решение

#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_stream создается, который является подклассом ostringstream. Отказ Все операции на эту временную работу, как они будут на ostringstream.

Когда утверждение заканчивается (т. Е. Сразу после точка запятой на всей операции печати в главном ()), временный объект выходит из прицела и разрушен. То my_stream деструктор звонит ThreadSafeLogging с данными «собраны» ранее.

Испытано (G ++).

Спасибо / Кредиты динго за то, как указывать, как упростить все это, поэтому мне не нужен перегруженный operator<<. Отказ Слишком плохие апартаменты не могут быть разделены.

Другие советы

Разве вы не могли вы только что вытеснить из Ostream и предоставьте собственную реализацию в потоке? Тогда вы могли бы просто сделать

myCOutObject << 1 << "hello world" << blah->getValue() << std::endl;

И получить точную те же функциональность без макросов и правильно использовать C ++?

Нет. Проблема в том, что без использования синтаксиса функций макрос ограничен только с заменой, где он есть.

Но если вы были готовы использовать функциональный синтаксис, вы можете заменить вещи как до и после args.

my_macro(1 << "hello world" << blah->getValue() << std::endl);

Вы могли, определить MyMacro как:

#define my_macro(args) std::ostreamstring oss; \
                       oss << args; \
                       ThreadSafeLogging(oss.str());

Взгляни на Google Glog, они делают это, используя временный объект, отлично с помощью

LOG(INFO) << "log whatever" << 1;

И у них также есть другие интересные макросы, такие как log_if et al.

Учитывая, что у вас есть эти строки где-то в вашем коде, да это возможно

#include <iostream>
#include <sstream> 

__LINE__ Макрос определяется всеми стандартными компиляторами. Таким образом, мы можем использовать его для создания имени переменной, который каждый раз другой, который вы используете макрос :)

Вот новая версия, которая рассматривается только в качестве инструкции по одному вопросу: (отредактировано)

#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__ (который не стандартный!). Благодаря Куксплесоне за этот совет

Вот еще один неприятный трюк, который я видел где-то еще. Он имеет значительный недостаток по сравнению с другим ответом: вы не можете использовать его дважды в том же объеме, потому что он объявляет переменную. Тем не менее, это все еще может быть интересно для разное случаи, когда вы хотите иметь 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;
}

Настройка журнала у меня очень похожа:

bool ShouldLog(const char* file, size_t line, Priority prio);

class LoggerOutput : public std::stringstream {
public:
  LoggerOutput(const char* file, size_t line, Priority prio) 
  : prio(prio) 
  {
    Prefix(file, line, prio);
  }
  void Prefix(const char* file, size_t line, Priority prio);
  ~LoggerOutput() {
    Flush();
  }
  void Flush();
private:
  Priority prio;
};

#define LOG(Prio) if (!Logging::ShouldLog(__FILE__, __LINE__, Prio)) {} else Logging::LoggerOutput(__FILE__, __LINE__, Prio)

Если ваша ведение журнала отключена, oStream никогда не создан, и мало накладных существует. Вы можете настроить регистрацию в журналах имени файла и номера строки или уровни (ы) приоритетов. Функция Sollog может изменяться между вызовами, поэтому вы можете дросселировать или ограничить вывод. Вывод журнала использует две функции, чтобы изменить сам, префикс, который добавляет префикс «файл: строку: (PRIO)» в строку, и FLUSH (), которые оба обмывают его на вывод журнала как одну команду, и добавляет ее в новую онлайн Отказ В моей реализации он всегда делает, но вы можете сделать это условным, если кто-то еще не там.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top