簡體   English   中英

如何在編譯時從 __FILE__ 獲取文件名並與 __LINE__ 連接

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

我試圖在編譯時連接文件名和沒有路徑的行。 /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;
}

但它似乎不起作用並返回編譯錯誤

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; std::array<_Tp, _Nm>::reference = char&; std::array<_Tp, _Nm>::value_type = char; std::array<_Tp, _Nm>::size_type = long unsigned int]'

有沒有辦法在編譯時做到這一點?

對於您的特定情況(獲取沒有路徑和行號的文件名),您可能想要使用一些更簡單的方法:


1. 使用__FILE_NAME__代替__FILE__

gcc 和 clang 都支持__FILE_NAME__宏,它只是解析為文件名而不是完整的文件路徑。

利用那些你可以把它寫成一個宏:


#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 不提供__FILE_NAME__宏,但您可以使用/FC編譯器開關來指定您是否需要__FILE__的完整路徑或只是文件名。

--

2.讓編譯器做字符串拼接

相鄰的字符序列由編譯器自動組合- 例如"a" "b" "c"將組合成"abc"

您可以使用它讓編譯器為您進行連接。
之后,我們可以將指向該組合字符串的指針遞增到最后一個斜杠以修剪路徑:

#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;

您正在獲取臨時數組的地址。 實際上首先存儲數組,然后獲取地址。

  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