【问题标题】:How should I make std::filesystem appear standards-conforming to Visual Studio 2015我应该如何使 std::filesystem 出现符合 Visual Studio 2015 的标准
【发布时间】:2018-02-01 22:42:37
【问题描述】:

我有一个项目目前锁定在 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。然而,这是一个函数,而不是一个类,所以同样的技术是行不通的。

我认为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)>'

函数有两个重载(一个接受第二个参数来返回错误代码而不是抛出异常)。

我被困住了。这必须是可能的,但我的 C++-foo 很弱。

【问题讨论】:

  • 我认为扩展 std 命名空间是未定义的行为。 stackoverflow.com/questions/37541022/…
  • @MFisherKDX 我明白,未定义意味着未定义。但是,如果您用foo 替换std,行为将是相同的。在这种情况下,我认为扩展它是合理的,因为我添加的符号在标准的更高版本中。
  • 我不认为using std::filesystem = std::experimental::filesystem::v1 有效?
  • @jwm .. 好的,我明白了。你能像这个例子一样先转换函数吗? stackoverflow.com/questions/30393285/…
  • @MarkRansom 应该是namespace std { namespace filesystem = experimental::filesystem::v1; },但我喜欢这个主意。

标签: c++ visual-studio-2015 std-filesystem


【解决方案1】:

答案在于错误消息,以及为重载方法实例化std::function 所需的帮助。感谢MFisherKDX 指点我hereW.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>

改为

【讨论】:

    猜你喜欢
    • 2019-02-27
    • 1970-01-01
    • 2020-09-27
    • 1970-01-01
    • 2016-01-24
    • 2015-10-20
    • 1970-01-01
    • 2016-07-26
    • 1970-01-01
    相关资源
    最近更新 更多