簡體   English   中英

如何確定是否使用<filesystem>或者<experimental/filesystem> ?

[英]How to determine whether to use <filesystem> or <experimental/filesystem>?

有沒有辦法確定我是否可以使用標准<filesystem> (在所有支持 C++17 的現代 C++ 編譯器上都可用)或<experimental/filesystem>舊編譯器使用的。 (例如 g++ 6.3,這是 Debian Stretch 上的當前標准版本)

知道使用哪個很重要,因為第一個使用std::filesystem::xxx ,后者使用std::experimental::filesystem::xxx

我通常創建一個包含以下內容的頭filesystem.hpp

// We haven't checked which filesystem to include yet
#ifndef INCLUDE_STD_FILESYSTEM_EXPERIMENTAL

// Check for feature test macro for <filesystem>
#   if defined(__cpp_lib_filesystem)
#       define INCLUDE_STD_FILESYSTEM_EXPERIMENTAL 0

// Check for feature test macro for <experimental/filesystem>
#   elif defined(__cpp_lib_experimental_filesystem)
#       define INCLUDE_STD_FILESYSTEM_EXPERIMENTAL 1

// We can't check if headers exist...
// Let's assume experimental to be safe
#   elif !defined(__has_include)
#       define INCLUDE_STD_FILESYSTEM_EXPERIMENTAL 1

// Check if the header "<filesystem>" exists
#   elif __has_include(<filesystem>)

// If we're compiling on Visual Studio and are not compiling with C++17, we need to use experimental
#       ifdef _MSC_VER

// Check and include header that defines "_HAS_CXX17"
#           if __has_include(<yvals_core.h>)
#               include <yvals_core.h>

// Check for enabled C++17 support
#               if defined(_HAS_CXX17) && _HAS_CXX17
// We're using C++17, so let's use the normal version
#                   define INCLUDE_STD_FILESYSTEM_EXPERIMENTAL 0
#               endif
#           endif

// If the marco isn't defined yet, that means any of the other VS specific checks failed, so we need to use experimental
#           ifndef INCLUDE_STD_FILESYSTEM_EXPERIMENTAL
#               define INCLUDE_STD_FILESYSTEM_EXPERIMENTAL 1
#           endif

// Not on Visual Studio. Let's use the normal version
#       else // #ifdef _MSC_VER
#           define INCLUDE_STD_FILESYSTEM_EXPERIMENTAL 0
#       endif

// Check if the header "<filesystem>" exists
#   elif __has_include(<experimental/filesystem>)
#       define INCLUDE_STD_FILESYSTEM_EXPERIMENTAL 1

// Fail if neither header is available with a nice error message
#   else
#       error Could not find system header "<filesystem>" or "<experimental/filesystem>"
#   endif

// We priously determined that we need the exprimental version
#   if INCLUDE_STD_FILESYSTEM_EXPERIMENTAL
// Include it
#       include <experimental/filesystem>

// We need the alias from std::experimental::filesystem to std::filesystem
namespace std {
    namespace filesystem = experimental::filesystem;
}

// We have a decent compiler and can use the normal version
#   else
// Include it
#       include <filesystem>
#   endif

#endif // #ifndef INCLUDE_STD_FILESYSTEM_EXPERIMENTAL

如果使用實驗頭std::experimental::filesystem ,它甚至會為std::experimental::filesystem創建一個別名到std::filesystem
這意味着您可以簡單地包含這個頭文件來代替<filesystem> ,使用std::filesystem::xxx並享受舊編譯器的支持。

關於此代碼段的詳細信息的一些說明:

  • __cpp_lib_filesystem__cpp_lib_experimental_filesystem
    這些是功能測試宏 當相應的標頭可用時,它們應該可用。 但是 VisualStudio 2015(及以下)不支持它們。 所以剩下的只是確保我們可以做出准確的評估,而不是依賴不可靠的宏。
  • __has_include()
    雖然大多數編譯器都內置了該宏,但沒有保證,因為它不在標准中。 我的代碼片段在使用之前會檢查它是否存在。 如果它不存在,我們假設我們必須使用實驗版本來提供最大的兼容性。
  • defined(_MSC_VER) && !(defined(_HAS_CXX17) && _HAS_CXX17)
    某些版本的 VisualStudio(即 2015)只有一半的 C++17 實現。 並且<filesystem>標頭可能存在,但std::filesystem不存在。 這一行檢查這種情況並使用實驗版本。
  • #error ...
    如果頭檢查可用並且我們找不到任何一個頭,我們只會打印一個很好的錯誤,因為我們無能為力。
  • INCLUDE_STD_FILESYSTEM_EXPERIMENTAL
    您甚至會得到一個 marco,讓您知道正在使用哪個版本,這樣您就可以編寫自己的預處理器語句來處理版本之間的差異。
  • namespace filesystem = experimental::filesystem;
    這個別名定義只是為了說服你有std::filesystem ,假設你的編譯器讓你這樣做(我沒有看到一個不允許這樣做的)。
    根據標准,在std命名空間中定義任何東西都是未定義的行為。 因此,如果您的編譯器、良心、同事、代碼標准或任何抱怨,只需定義namespace fs = std::experimental::filesystem; 在上塊和namespace fs = std::filesystem; 在較低。 (可以肯定的是,如果您這樣做,請刪除namespace std {東西)

PS:我創建了答案和這個問題,因為我花了很多時間對沒有<filesystem>標頭的舊編譯器感到沮喪。 在具有多個編譯器和多個版本的多個平台上進行了大量研究和測試后,我設法提出了這個通用解決方案。 我已經用 VisualStudio、g++ 和 clang 對其進行了測試(僅適用於實際上至少對 C++17 具有實驗性支持的版本)。
如果另一個編譯器有問題,請告訴我,我也會讓它為它工作。

對於此類問題,我通常會大量使用功能測試宏 我目前正面臨這個確切的問題,但我使用了__cpp_lib_filesystemusing關鍵字。

// since C++ 20
#include <version>

#ifdef __cpp_lib_filesystem
    #include <filesystem>
    using fs = std::filesystem;
#elif __cpp_lib_experimental_filesystem
    #include <experimental/filesystem>
    using fs = std::experimental::filesystem;
#else
    #error "no filesystem support ='("
#endif

我在 gcc-6 及更高版本以及 clang-6 上使用它,遺憾的是沒有舊的工作室副本可供測試,但它適用於 15.7 及更高版本。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM