【问题标题】:No operator+ for std::filesystem::path?std::filesystem::path 没有 operator+?
【发布时间】:2021-01-27 11:03:03
【问题描述】:

可以使用/ 运算符在一行中append 多个路径:

  std::filesystem::path p1{"A"};
  auto p2 = p1 / "B" / "C";

比较方便。但是,concat 只提供+=

  std::filesystem::path p1{"A"};
  auto p2 = p1 / "B" / "C" + ".d";   // NOT OK

这很烦人,因为我无法轻松地将扩展名添加到路径的末尾。我别无选择,只能写类似

  std::filesystem::path p1{"A"};
  auto p2 = p1 / "B" / "C";
  p2 += ".d";

我错过了什么吗?这种不一致是否有原因?

【问题讨论】:

  • 不。没有别的办法
  • @KamilCuk 不能使用const char[N],那就是auto p2 = p1 / "B" / (std::string("C") + ".d");
  • ("C" + ".d") 添加两个const char[2]s
  • @KamilCuk 像“A”这样的字符串文字的类型是“const char[N]”,并且在使用运算符 + 时将转换为“const char*”,因此您要添加两个指针"A"+"B"
  • 太棒了。 auto p2 = p1 / "B" / "C" += ".d";auto p2 = p1 / "B" / (std::string() + "C" + ".d"); :D 。这两个都在godbolt 中工作。 note that in practice, "C" will most likely 不是在实践中,无论如何p1 / "B" / "C" 的结果类型为std::filesystem::path,所以它在上面做+=。不过,这不是一个答案,因为我不知道“这种不一致的原因”。

标签: c++ std-filesystem


【解决方案1】:

这有点推测,但我认为这是因为operator+ 很容易与operator/ 混淆。如果按以下方式使用,则会导致错误

path p2{"/"};
auto p1 = p2 + "A" + "B";
// Wants /A/B, gets /AB

使用字符串文字使解决方法更好:

using namespace std::literals;
std::filesystem::path p1{"A"};
auto p2 = p1 / "B" / ("C"s + ".d");   

在这里,"C"s 创建了一个std::string,内容为C,然后我们使用std::stringoperator+。如果"C" 部分本身已经是一条路径(否则您可以只写"C.d" 开头),您可以这样做

std::filesystem::path p1{"A"}, c_path{"C"};
auto p2 = p1 / "B" / (c_path += ".d");   

因为operator+= 返回结果对象。 (这有点浪费,但我可以想象编译器会优化它)。

【讨论】:

    【解决方案2】:

    虽然可能是因为 std::string 和 const char * 隐式转换为 std::filesystem::path。这里有一些 c++20 非常小心以避免不必要的隐式转换。

    #include <concepts>
    #include <filesystem>
    #include <iostream>
    #include <string>
    using namespace std::string_literals;
    template <typename T, typename U>
    requires std::same_as<std::decay_t<T>, std::filesystem::path> &&
        (!std::same_as<std::decay_t<U>, std::filesystem::path>) && 
            std::convertible_to<std::decay_t<U>, std::filesystem::path>
        inline std::filesystem::path
            operator+(const T &lhs, const U &rhs) {
        auto tmp = lhs;
        tmp += rhs;
        return tmp;
    }
    
    template <typename T>
    requires std::same_as<std::decay_t<T>, std::filesystem::path> ||
        std::same_as<std::decay_t<T>, std::filesystem::directory_entry>
    inline std::filesystem::path operator+(const std::filesystem::path &lhs,
                                           const T &rhs) {
        auto tmp = lhs;
        tmp += rhs;
        return tmp;
    }
    int main() {
        std::cout << "aaa" + std::filesystem::path{"bbb"} << '\n';
        std::cout << "aaa"s + std::filesystem::path{"bbb"} << '\n';
        std::cout << std::filesystem::directory_entry{"aaa"} +
                         std::filesystem::path{"bbb"}
                  << '\n';
    
        std::cout << std::filesystem::path{"aaa"} + "bbb" << '\n';
        std::cout << std::filesystem::path{"aaa"} + "bbb"s << '\n';
        std::cout << std::filesystem::path{"aaa"} +
                         std::filesystem::directory_entry{"bbb"}
                  << '\n';
    
        std::cout << std::filesystem::path{"aaa"} + std::filesystem::path{"bbb"}
                  << '\n';
        std::cout << std::filesystem::directory_entry{"aaa"} +
                         std::filesystem::directory_entry{"bbb"}
                  << '\n';
    }
    

    【讨论】:

      【解决方案3】:

      如果您只需要添加扩展,您也可以这样做:

      std::filesystem::path p1{"A"};
      auto p2 = (p1 / "B" / "C").replace_extension(".d");
      

      【讨论】:

        猜你喜欢
        • 2018-02-18
        • 2011-04-23
        • 2019-11-06
        • 1970-01-01
        • 1970-01-01
        • 2012-01-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多