Подтвердить что ты не робот

Передача вызывающего __FILE__ __LINE__ функции без использования макроса

Я привык к этому:

class Db {
  _Commit(char *file, int line) {
    Log("Commit called from %s:%d", file, line);
  }
};

#define Commit() _Commit(__FILE__, __LINE__)

но большая проблема в том, что я переопределяю слово Commit глобально, а в инфраструктуре приложений 400 тыс. строк это проблема. И я не хочу использовать определенное слово, например DbCommit: мне не нравятся сокращения, например db->DbCommit(), или для передачи значений вручную везде: db->Commit(__FILE__, __LINE__) хуже.

Итак, любой совет?

4b9b3361

Ответ 1

Итак, вы хотите сделать запись (или что-то еще) с информацией о файле и строке, и вы предпочитаете не использовать макросы, правильно?

В конце дня его просто невозможно сделать на С++. Независимо от того, какой механизм вы выбрали - будь то встроенные функции, шаблоны, параметры по умолчанию или что-то еще - если вы не используете макрос, вы просто получите имя файла и номер строки функции ведения журнала, а не точка вызова.

Использовать макросы. Это одно место, где они действительно не подлежат замене.

EDIT:

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

EDIT2:

Как говорит Натон в комментариях ниже, в тех случаях, когда вы используете макросы, лучше всего говорить об этом. Укажите макрокоманды макросов, например COMMIT(), а не COMMIT(). Это позволит сторонам и отладчикам понять, что происходит макросообщение, и в большинстве случаев это должно помочь избежать столкновений. Обе хорошие вещи.

Ответ 2

Вы можете использовать комбинацию параметра по умолчанию и трюк препроцессора для передачи файла вызывающего абонента в функции. Это следующее:

  • Объявление функции:

    static const char *db_caller_file = CALLER_FILE;
    
    class Db {
        _Commit(const char *file = db_caller_file) {
        Log("Commit called from %s", file);
      }
    };
    
  • Объявить переменную db_caller_file в файле заголовка класса. Каждая единица перевода будет иметь const char *db_caller_file. Он статичен, поэтому он не будет мешать между единицами перевода. (Нет нескольких объявлений).

  • Теперь объект CALLER_FILE, это макрос и будет создан из параметров командной строки gcc. Фактически, если вы используете автоматическую систему Make, где есть общее правило для исходных файлов, это намного проще: вы можете добавить правило для определения макроса с именем файла в качестве значения. Например:

    CFLAGS= -MMD -MF $(DEPS_DIR)/$<.d  -Wall -D'CALLER_FILE="$<"'
    

-D определяет макрос перед компиляцией этого файла. $< Производит подстановку для имени предпосылки для правила, которое в этом случае является именем исходного файла. Таким образом, каждая единица перевода будет иметь свою собственную переменную db_caller_file со значением строка, содержащую имя файла.

Та же идея не может быть применена для строки вызывающего абонента, так как каждый вызов в одной и той же системе переводов должен иметь разные номера строк.