简体   繁体   English

如何在编译时从 __FILE__ 获取文件名并与 __LINE__ 连接

[英]How to get filename from __FILE__ and concat with __LINE__ at compile time

I'm trying to concat filename and line without path at compile time.我试图在编译时连接文件名和没有路径的行。 Like /tmp/main.cpp20 -> main.cpp:20/tmp/main.cpp20 -> main.cpp:20

#include <array>
#include <iostream>
using namespace std;

#define STRINGIZE(x) STRINGIZE2(x)
#define STRINGIZE2(x) #x
#define LINE_STRING STRINGIZE(__LINE__)

constexpr const char* file_name(const char* path) {
  const char* file = path;
  while (*path) {
    if (*path++ == '/') {
      file = path;
    }
  }
  return file;
}

constexpr std::size_t str_size(const char* str) {
  auto i = str;
  while (*i != '\0') ++i;
  const auto length = i - str;
  return length;
}

template <std::size_t N1, std::size_t N2>
constexpr std::array<char, N1 + N2 + 2> formatFilename(const char* name,
                                                       const char* line) {
  auto total_size = N1 + N2 + 2;
  std::array<char, N1 + N2 + 2> res{};
  std::size_t i = 0;
  for (; i < N1; ++i) {
    res[i] = name[i];
  }
  res[i++] = ':';
  for (int j = 0; j < N2; ++j) {
    res[i + j] = line[j];
  }
  res[total_size - 1] = '\0';
  return res;
}

int main() {
  constexpr char *p = &(
      formatFilename<str_size(file_name(__FILE__)), str_size(LINE_STRING)>(
          file_name(__FILE__), LINE_STRING)[0]);
  cout << p << endl;
}

But it seems not work and return a compilation error但它似乎不起作用并返回编译错误

main.cpp: In function 'int main()': main.cpp:46:46: error: call to non-'constexpr' function 'std::array<_Tp, _Nm>::value_type& std::array<_Tp, _Nm>::operator[](std::array<_Tp, _Nm>::size_type) [with _Tp = char; main.cpp:在函数'int main()'中:main.cpp:46:46:错误:调用非'constexpr'函数'std::array<_Tp,_Nm>::value_type& std::array<_Tp , _Nm>::operator[](std::array<_Tp, _Nm>::size_type) [with _Tp = char; long unsigned int _Nm = 12; long unsigned int _Nm = 12; std::array<_Tp, _Nm>::reference = char&; std::array<_Tp, _Nm>::reference = char&; std::array<_Tp, _Nm>::value_type = char; std::array<_Tp, _Nm>::value_type = char; std::array<_Tp, _Nm>::size_type = long unsigned int]' std::array<_Tp, _Nm>::size_type = long unsigned int]'

Is there any way to do it at compile time?有没有办法在编译时做到这一点?

For your specific case (getting the filename without path and the line number) there are a few easier approaches that you might want to use:对于您的特定情况(获取没有路径和行号的文件名),您可能想要使用一些更简单的方法:


1. Using __FILE_NAME__ instead of __FILE__ 1. 使用__FILE_NAME__代替__FILE__

Both gcc and clang support the __FILE_NAME__ macro, that just resolves to the filename instead of the full file path. gcc 和 clang 都支持__FILE_NAME__宏,它只是解析为文件名而不是完整的文件路径。

Utilizing those you can write it as a single macro:利用那些你可以把它写成一个宏:


#define STRINGIFY(x) STRINGIFY_IMPL(x)
#define STRINGIFY_IMPL(x) #x

#define FILENAME __FILE_NAME__ ":" STRINGIFY(__LINE__)

// Usage:
constexpr char* foo = FILENAME;
std::cout << foo << std::endl;

msvc unfortunately doesn't offer the __FILE_NAME__ macro, but you could utilize the /FC compiler switch to specify if you want the full path for __FILE__ or just the filename.不幸的是,msvc 不提供__FILE_NAME__宏,但您可以使用/FC编译器开关来指定您是否需要__FILE__的完整路径或只是文件名。

-- --

2. Let the compiler do the string concatenation 2.让编译器做字符串拼接

Adjacent character sequences are automatically combined by the compiler - eg "a" "b" "c" would be combined into "abc" .相邻的字符序列由编译器自动组合- 例如"a" "b" "c"将组合成"abc"

You can use this to let the compiler do the concatenation for you.您可以使用它让编译器为您进行连接。
After that we can just increment the pointer to that combined string past the last slash to trim off the path:之后,我们可以将指向该组合字符串的指针递增到最后一个斜杠以修剪路径:

#define STRINGIFY(x) STRINGIFY_IMPL(x)
#define STRINGIFY_IMPL(x) #x
#define FILENAME __FILE__ ":" STRINGIFY(__LINE__)

constexpr const char* filename_without_path(const char* path) {
    const char* result = path;
    while(*path != '\0')
        if(*path++ == '/') result = path;

    return result;
}

// Usage:
constexpr const char* foo = filename_without_path(FILENAME);
std::cout << foo << std::endl;

You are taking an address of a temporary array.您正在获取临时数组的地址。 Actually first store the array, then take the address.实际上首先存储数组,然后获取地址。

  constexpr auto p = // stores the array
      formatFilename<str_size(file_name(__FILE__)), str_size(LINE_STRING)>(
          file_name(__FILE__), LINE_STRING);
  // than take the address
  cout << p.data() << endl;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM