有没有一种方法可以确定我是否可以使用标准的<filesystem>
(在所有支持C ++ 17的现代C ++编译器中都可以使用)还是<experimental/filesystem>
(由较早的编译器使用)。 (例如g ++ 6.3,这是Debian Stretch上的当前标准版本)
知道要使用哪个是重要的,因为前者使用std::filesystem::xxx
,后者使用std::experimental::filesystem::xxx
。
答案 0 :(得分:8)
我通常创建带有以下内容的标头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::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 {
内容) P.S .:我创建了答案和这个问题,因为我花了很多时间对没有<filesystem>
头的较旧的编译器感到沮丧。在具有多个编译器和版本的多个平台上进行了大量研究和测试之后,我设法提出了这个通用解决方案。我已经用VisualStudio,g ++和clang对其进行了测试(仅在实际上至少具有对C ++ 17的实验支持的版本中)。
如果其他编译器有问题,请告诉我,我也将使其解决问题。
答案 1 :(得分:2)
对于这种类型的问题,我通常会大量使用feature test macros。我目前面临这个确切的问题,但是我将__cpp_lib_filesystem
和using
关键字一起使用了。
#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上使用它,遗憾的是没有旧版本的Studio可以用来测试,但是它可以在15.7和更高版本上使用。