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

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

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__) является худшим.

Итак, какой совет?

Ответы [ 2 ]

49 голосов
/ 16 ноября 2010

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

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

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

РЕДАКТИРОВАТЬ:

Даже в C ++ FAQ говорится, что макросы иногда являются меньшим из двух зол.1012 * EDIT2:

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

0 голосов
/ 26 февраля 2015

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

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

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

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

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

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

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

...