Как объединить __func__ и __LINE__ в определении макроса - PullRequest
2 голосов
/ 01 мая 2020

Я хотел бы определить макрос для конкатата __func__ (или __FUNCTION__) с __LINE__:

Следующее отлично работает:

// macro_test.cc
#include <iostream>

#define STR2(X) #X
#define STR(X) STR2(X)
#define FILE_LOCATION __FILE__ ":" STR(__LINE__) " "

int main() {
  std::cout << FILE_LOCATION << "is <file_name>:<line_number>" << std::endl;
  return 0;
}

А вот output

$ ./a.out 
macro_test.cc:8 is <file_name>:<line_number>

Однако следующее приводит к ошибке компиляции (I только что заменил __FILE__ на __func__):

// macro_test.cc
#include <iostream>

#define STR2(X) #X
#define STR(X) STR2(X)
#define FUNC_LOCATION __func__ ":" STR(__LINE__) " "

int main() {
  std::cout << FUNC_LOCATION << "is <function_name>:<line_number>" << std::endl;
  return 0;
}

~$ gcc macro_test.cc 
macro_test.cc: In function ‘int main()’:
macro_test.cc:5:32: error: expected ‘;’ before string constant
 #define FUNC_LOCATION __func__ ":" STR(__LINE__) " "
                                ^
macro_test.cc:8:16: note: in expansion of macro ‘FUNC_LOCATION’
   std::cout << FUNC_LOCATION << "is <function_name>:<line_number>" << std::endl;

Кто-нибудь знает причину для этого и как мне этого добиться?

Я использую g cc 5.4.0 на Linux (Ubuntu 18.04).

Ответы [ 2 ]

5 голосов
/ 01 мая 2020

выдает ошибку компиляции [...] кто-нибудь знает причину этого

__func__ является переменной:

static const char __func__[] = "function-name";

Это , а не для (строкового) литерала (к которому, например, __FILE__ "расширяется".)

(документы здесь: https://gcc.gnu.org/onlinedocs/gcc/Function-Names.html )

2 голосов
/ 01 мая 2020

Вместо того, чтобы пытаться объединить несовместимые типы в одну строку, вы можете использовать немедленно вызванное выражение функции (заимствование из терминологии JavaScript) в качестве реализации макроса.

Так как он выполняется немедленно, я передаю два идентификатора препроцессора в качестве параметров.

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

#include <sstream>
#define FUNC_LOCATION \
    [](auto fn, auto ln) { \
        std::stringstream ss;
        ss << fn << ":" << ln << " "; \
        return ss.str(); \
    }(__func__, __LINE__)

int main() {
    std::cout << FILE_LOCATION << "is <file_name>:<line_number>" << std::endl;
    return 0;
}
...