[英]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
__has_include()
defined(_MSC_VER) && !(defined(_HAS_CXX17) && _HAS_CXX17)
<filesystem>
標頭可能存在,但std::filesystem
不存在。 這一行檢查這種情況並使用實驗版本。#error ...
INCLUDE_STD_FILESYSTEM_EXPERIMENTAL
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_filesystem
和using
關鍵字。
// 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.