我应该如何使 std::filesystem 看起来符合 Visual Studio 2015 标准
How should I make std::filesystem appear standards-conforming to Visual Studio 2015
我有一个项目目前锁定在 Visual Studio 2015 年。但是,我想编写尽可能符合标准的代码。
我想使用 std::filesystem
但它直到 C++-17 才成为标准。幸运的是,几乎所有东西都可用,就在 std::experimental::filesystem::v1
命名空间中。我不喜欢一揽子 using
指令;我更喜欢全面地界定事物的范围,以明确事物的来源。所以我不会只放入一个全局 using
语句。需要一些魔法来说服编译器做我想做的事。
这是我的第一次尝试:
#include <filesystem>
#if defined(_MSC_VER) && _MSC_VER <= 1900 // VS 2015
namespace std {
namespace filesystem {
using path = std::experimental::filesystem::v1::path;
}
}
#endif
效果很好,std::filesystem::path
现在可以访问了。我已经测试了创建和使用 path
对象并且它有效。
随着我的前进,我知道我需要更多的东西。我想知道是否有办法将整个东西引入:
namespace std {
namespace filesystem {
using std::experimental::filesystem::v1;
}
}
这似乎是一种倒退。似乎什么都看不见。事后看来,我想这是有道理的,因为 using
语句的范围以下一行的右大括号结束。
接下来,我想要一个directory_entry
。同样的技术似乎有效
namespace std {
namespace filesystem {
using directory_entry = std::experimental::filesystem::v1::directory_entry;
}
}
再一次,编译器似乎很高兴。
现在,我想使用 std::directory::create_directories
。但是,这是一个函数,而不是 class,所以同样的技术不会奏效。
我认为 std::function
可能是为此量身定做的,但我没有任何运气。我试过了
namespace std {
namespace filesystem {
function<bool(path)> create_directories = std::experimental::filesystem::v1::create_directories;
}
}
编译器说
Error C2440 'initializing': cannot convert from 'overloaded-function' to 'std::function<bool (std::filesystem::path)>'
该函数有两个重载(一个将第二个参数作为 return 错误代码而不是抛出异常)。
我卡住了。这必须是可能的,但我的 C++-foo 很弱。
答案在于错误消息,以及为重载方法实例化 std::function
所需的帮助。感谢 MFisherKDX for pointing me and to W.F. 提供有效的答案。
忽略扩展标准命名空间是否合法、道德或是否符合品味的问题(因为在这种情况下,我相信它至少是 3 个中的 2 个),这是我完整评论的解决方法:
#if defined(_MSC_VER) && _MSC_VER <= 1900
// Visual Studio 2015 work-around ...
// std::filesystem was incorporated into C++-17 (which is obviously after VS
// 2015 was released). However, Microsoft implemented the draft standard in
// the std::exerimental namespace. To avoid nasty ripple effects when the
// compiler is updated, make it look like the standard here
#include <functional>
namespace std {
namespace filesystem {
using directory_entry = std::experimental::filesystem::v1::directory_entry;
using directory_iterator = std::experimental::filesystem::v1::directory_iterator;
function<bool(path const&)> create_directories =
static_cast<bool(*)(path const&)>(
std::experimental::filesystem::v1::create_directories);
}
}
#endif
更新:Sebastian 有最简单的解决方案。
#if defined(_MSC_VER) && _MSC_VER <= 1900
// Visual Studio 2015 work-around ...
// std::filesystem was incorporated into C++-17 (which is obviously after VS
// 2015 was released). However, Microsoft implemented the draft standard in
// the std::exerimental namespace. To avoid nasty ripple effects when the
// compiler is updated, make it look like the standard here
namespace std {
namespace filesystem = experimental::filesystem::v1;
}
#endif
顺便说一下,gcc 7.3 需要几乎完全相同的解决方法,除了你不能
#include <filesystem>
但必须
#include <experimental/filesystem>
改为
我有一个项目目前锁定在 Visual Studio 2015 年。但是,我想编写尽可能符合标准的代码。
我想使用 std::filesystem
但它直到 C++-17 才成为标准。幸运的是,几乎所有东西都可用,就在 std::experimental::filesystem::v1
命名空间中。我不喜欢一揽子 using
指令;我更喜欢全面地界定事物的范围,以明确事物的来源。所以我不会只放入一个全局 using
语句。需要一些魔法来说服编译器做我想做的事。
这是我的第一次尝试:
#include <filesystem>
#if defined(_MSC_VER) && _MSC_VER <= 1900 // VS 2015
namespace std {
namespace filesystem {
using path = std::experimental::filesystem::v1::path;
}
}
#endif
效果很好,std::filesystem::path
现在可以访问了。我已经测试了创建和使用 path
对象并且它有效。
随着我的前进,我知道我需要更多的东西。我想知道是否有办法将整个东西引入:
namespace std {
namespace filesystem {
using std::experimental::filesystem::v1;
}
}
这似乎是一种倒退。似乎什么都看不见。事后看来,我想这是有道理的,因为 using
语句的范围以下一行的右大括号结束。
接下来,我想要一个directory_entry
。同样的技术似乎有效
namespace std {
namespace filesystem {
using directory_entry = std::experimental::filesystem::v1::directory_entry;
}
}
再一次,编译器似乎很高兴。
现在,我想使用 std::directory::create_directories
。但是,这是一个函数,而不是 class,所以同样的技术不会奏效。
我认为 std::function
可能是为此量身定做的,但我没有任何运气。我试过了
namespace std {
namespace filesystem {
function<bool(path)> create_directories = std::experimental::filesystem::v1::create_directories;
}
}
编译器说
Error C2440 'initializing': cannot convert from 'overloaded-function' to 'std::function<bool (std::filesystem::path)>'
该函数有两个重载(一个将第二个参数作为 return 错误代码而不是抛出异常)。
我卡住了。这必须是可能的,但我的 C++-foo 很弱。
答案在于错误消息,以及为重载方法实例化 std::function
所需的帮助。感谢 MFisherKDX for pointing me
忽略扩展标准命名空间是否合法、道德或是否符合品味的问题(因为在这种情况下,我相信它至少是 3 个中的 2 个),这是我完整评论的解决方法:
#if defined(_MSC_VER) && _MSC_VER <= 1900
// Visual Studio 2015 work-around ...
// std::filesystem was incorporated into C++-17 (which is obviously after VS
// 2015 was released). However, Microsoft implemented the draft standard in
// the std::exerimental namespace. To avoid nasty ripple effects when the
// compiler is updated, make it look like the standard here
#include <functional>
namespace std {
namespace filesystem {
using directory_entry = std::experimental::filesystem::v1::directory_entry;
using directory_iterator = std::experimental::filesystem::v1::directory_iterator;
function<bool(path const&)> create_directories =
static_cast<bool(*)(path const&)>(
std::experimental::filesystem::v1::create_directories);
}
}
#endif
更新:Sebastian 有最简单的解决方案。
#if defined(_MSC_VER) && _MSC_VER <= 1900
// Visual Studio 2015 work-around ...
// std::filesystem was incorporated into C++-17 (which is obviously after VS
// 2015 was released). However, Microsoft implemented the draft standard in
// the std::exerimental namespace. To avoid nasty ripple effects when the
// compiler is updated, make it look like the standard here
namespace std {
namespace filesystem = experimental::filesystem::v1;
}
#endif
顺便说一下,gcc 7.3 需要几乎完全相同的解决方法,除了你不能
#include <filesystem>
但必须
#include <experimental/filesystem>
改为