2015-10-19 4 views
0

Я хотел бы написать функцию для ведения журнала, который должен быть использован, как это:Функция регистрации, которая использует оператор <<

log(__FILE__) << "My message containing integer: " << 123 << " and double: " << 1.2; 

Это должно напечатать следующую строку, добавьте Endl и немедленно промойте:

main.cpp: My сообщение, содержащее целое число: 123 и дважды: 1,2

Мои (упрощенный) попытка для реализации функции:

class Writer 
{ 
public: 
    template<typename T> 
    Writer & operator<<(T t) 
    { 
     cout << t << endl; 
     cout.flush(); 
     return (*this); 
    } 
}; 

Writer log(const char* fileName) 
{ 
    cout << fileName << ": "; 
    return Writer(); 
} 

int main(int argc, const char *argv[]) 
{ 
    log(__FILE__) << "My message containing integer: " << 123 << "and double: " << 1.2; 
    return 0; 
} 

Моя проблема заключается в том, что из-за LR ассоциативности оператора < < выход:

main.cpp: My сообщение, содержащее число:

и дважды:

1.2

Есть ли способ реализовать эту функцию или мое требование для ее использования неосуществимо?

В идеале я бы хотел использовать простой C++ 03 (т. Е. Нет возможностей C++ 11, повысить и нестандартные библиотеки).

+0

Просто, чтобы быть ясным: что нужно очищать, когда и что должно быть на какой линии? Например: где эта часть «double ...» входит в ваш первый пример? –

+0

@BaummitAugen Извините, отредактировано, исправлено. – bedrorom

ответ

3

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

Простое решение вашей проблемы:

class Writer 
{ 
public: 
    template<typename T> 
    Writer & operator<<(T t) 
    { 
     cout << t; 
     return (*this); 
    } 

    ~Writer() 
    { 
     try { 
      cout << endl; 
     } 
     catch (...) { 
      // You have to make sure that no 
      // exception leaves destructor 
     } 
    } 
}; 

Стоит также заметить, что ваш подход не очень масштабируемым: нельзя использовать код в многопоточной среде. Предположим, что два потока писать в ваш протоколирования:

Thread 1: log(__FILE__) << "a" << "b" << "c"; 
Thread 2: log(__FILE__) << "a" << "b" << "c"; 

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

Чтобы избежать этого, вы можете иметь статический объект mutex внутри функции log(), которую вы передаете в конструктор Writer. Затем вам нужно заблокировать его в конструкторе и разблокировать его в деструкторе. Это гарантирует синхронизацию одновременной записи разных записей.

+1

положите попытку вокруг этого кода деструктора, и я дам вам +1 –

+0

. Зачем вам нужен try/catch? –

+0

Технически, Ричард прав: cout << endl может выдать исключение, но исключение из деструкторов - это совершенно неверная идея (об этом вы можете многое узнать в Интернете). Поэтому необходимо, чтобы все деструкторы не метали. Я не хотел загромождать код, поэтому я поставил пример как можно более коротким, но теперь я думаю, что хорошо уделить особое внимание этой проблеме в моем отрезании, потому что не все знают о важности этого.Поэтому я добавил проверку исключений. –