std::filesy...::proximate(3)

πŸ“¦ version 2024.07.05, in nixpkgs unstable, opensuse-leap 16.0

πŸ’… std::filesystem::relative, std::filesystem::proximate πŸ’…

Okay bestie, so this is from the C++ Standard Library and honestly? These two functions are about to become your new faves. They're both in the <filesystem> header, both since C++17, and both are out here doing that path math so you don't have to. Let's get into it ✨


🌸 SYNOPSIS 🌸

So like, this is defined in the header <filesystem>, periodt. Here's the whole lineup of what we're working with:

path relative( const std::filesystem::path& p,
               std::error_code& ec );

(1) β€” since C++17

path relative( const std::filesystem::path& p,
               const std::filesystem::path& base =
               std::filesystem::current_path() );

(2) β€” since C++17

path relative( const std::filesystem::path& p,

               const std::filesystem::path& base,
               std::error_code& ec );

(3) β€” since C++17

path proximate( const std::filesystem::path& p,
                std::error_code& ec );

(4) β€” since C++17

path proximate( const std::filesystem::path& p,
                const std::filesystem::path& base =
                std::filesystem::current_path() );

(5) β€” since C++17

path proximate( const std::filesystem::path& p,

                const std::filesystem::path& base,
                std::error_code& ec );

(6) β€” since C++17


✨ DESCRIPTION ✨

  1. Okay so this one literally just returns relative(p, current_path(), ec). Like, that's it. It's the current_path() flavored version.
  2. & 3. These return p made relative to base. And bestie, listen β€” it resolves symlinks and normalizes both p and base before any other processing. It's giving thorough. Effectively it returns:
std::filesystem::weakly_canonical(p).lexically_relative(std::filesystem::weakly_canonical(base))

or the error-code flavor:

std::filesystem::weakly_canonical(p, ec).lexically_relative(std::filesystem::weakly_canonical(base, ec))

with one big caveat β€” the error code form returns path() at the first error occurrence, if any. So like, it bails on the first oopsie πŸ’€

  1. This one returns proximate(p, current_path(), ec). Same energy, different function.
  2. & 6. Effectively returns:
std::filesystem::weakly_canonical(p).lexically_proximate(std::filesystem::weakly_canonical(base))

or:

std::filesystem::weakly_canonical(p, ec).lexically_proximate(std::filesystem::weakly_canonical(base, ec))

And again, the error code form returns path() at the first error occurrence, if any. Consistency icon πŸ’–


🫢 PARAMETERS 🫢

  • p β€” an existing path πŸ‘‘
  • base β€” the base path, against which p will be made relative/proximate. It's the reference point, the main character we're measuring from.
  • ec β€” error code to store error status to. Like a lil note that says "hey something went wrong, here's what."

πŸ’– RETURN VALUE πŸ’–

  1. p made relative against current_path().
  2. & 3. p made relative against base.
  3. p made proximate against current_path().
  4. & 6. p made proximate against base.

Simple, clean, slay. ✨


😭 EXCEPTIONS 😭

Okay so, any overload not marked noexcept may throw std::bad_alloc if memory allocation fails. Like, sorry, the memory said no πŸ“‰

Overloads 2 and 5 throw std::filesystem::filesystem_error on underlying OS API errors, and it's constructed with:

  • p as the first path argument
  • base as the second path argument
  • the OS error code as the error code argument

Overloads 1, 3, 4, and 6 β€” the ✨error code girlies✨ β€” set a std::error_code& parameter to the OS API error code if an OS API call fails, and execute ec.clear() if no errors occur. Like "all clear, no notes" 🌈


πŸŽ€ EXAMPLE πŸŽ€

Run this code, bestie, I promise it's cute:

#include <filesystem>
#include <iostream>

void show(std::filesystem::path x, std::filesystem::path y)
{
    std::cout << "x:\t\t " << x << "\ny:\t\t " << y << '\n'
              << "relative(x, y):  "
              << std::filesystem::relative(x, y) << '\n'
              << "proximate(x, y): "
              << std::filesystem::proximate(x, y) << "\n\n";
}

int main()
{
    show("/a/b/c", "/a/b");
    show("/a/c", "/a/b");
    show("c", "/a/b");
    show("/a/b", "c");
}

πŸ’« Possible output πŸ’«

x:               "/a/b/c"
y:               "/a/b"
relative(x, y):  "c"
proximate(x, y): "c"

x:               "/a/c"
y:               "/a/b"
relative(x, y):  "../c"
proximate(x, y): "../c"

x:               "c"
y:               "/a/b"
relative(x, y):  ""
proximate(x, y): "c"

x:               "/a/b"
y:               "c"
relative(x, y):  ""
proximate(x, y): "/a/b"

The way the last two cases just give you different answers depending on the function β€” that's the whole point, and it's iconic. πŸ¦‹


🌟 SEE ALSO 🌟

  • path β€” represents a path (C++17) (class) β€” the OG.
  • absolute β€” composes an absolute path (C++17) (function) β€” makes things absolute, as one does.
  • canonical β€” composes a canonical path (function) β€” the fully resolved version of the truth.
  • weakly_canonical β€” (function) (C++17) β€” canonical but, like, chill about it.
  • lexically_normal β€” converts path to normal form β€” it normalizes, lexically.
  • lexically_relative β€” converts path to relative form β€” our relative bestie, lexical edition.
  • lexically_proximate β€” converts path to proximate form (public member function of std::filesystem::path) β€” the proximate icon, member-function style.

No cap, these functions are lowkey the backbone of filesystem navigation. If you EVER need to figure out "how do I get from here to there" in C++, this is your girl. ✨

Anyways bestie, that's the page πŸ’– This was pulled from cppreference.com, version 2024.06.10, and yeahβ€”go out there and make some paths relative and proximate. You're literally gonna do great. Periodt. πŸ‘‘πŸ«Ά

πŸ“¦ where this page comes from