c++c++17std-filesystem

Why is it not possible to construct a `std::filesystem::path` from `std::filesystem::path` iterators?


The following piece of code aims to strip the first part of a path in case it exists:

#include <filesystem>

std::filesystem::path strip_prefix(std::filesystem::path p)
{      
  if (auto it{p.begin()}; it != p.end())
  {
    ++it;
    return std::filesystem::path(it, p.end());
  }

  return p;
}

(See: https://godbolt.org/z/wkXhcw)

I was surprised to find out this does not work. The code does not compile since the path constructor only takes iterators that iterate over character sequences. I can see the use of that, but why limit construction to only those kind of iterators? In my opinion it is counter intuitive to not support constructing a path from its own iterators. As far as I know most other STL types do support this idiom.

What would be an efficient implementation to achieve the same goal, other than completely reconstructing a new path?

Update: in this context, I found the following discussion relevant/amusing: https://lists.boost.org/Archives/boost//2013/01/200409.php. I agree with Dave here. I think seeing a path as a container of path elements is a very natural way to look at it (from a programmer's perspective).


Solution

  • The simplest solution to the concatenating the segments to make a new path is just std::accumulate().

    For your particular use case, I'd do something like this:

    std::filesystem::path strip_prefix(std::filesystem::path p)
    {
        if(p.empty()) return p;
        return std::accumulate(std::next(p.begin()), p.end(), 
                               std::filesystem::path{}, std::divides{});
    }
    

    As for why there isn't a constructor (or maybe a free function) to do this? I don't know. This seems like a need that comes up a fair bit when working with paths, but the committee does tend to be reluctant to add convenience functions to standard classes if the same result can be achieved by a call to a standard algorithm.