directory_iterator and recursive_directory_iterator are not C++20 ranges
Barry Revzin

Created on 2020-08-27.00:00:00 last changed 2 weeks ago


Date: 2020-09-15.00:00:00

[ 2020-09-06; Reflector prioritization ]

Set priority to 3 during reflector discussions.

Date: 2020-08-27.00:00:00

std::filesystem::directory_iterator and std::filesystem::recursive_directory_iterator are intended to be ranges, but both fail to satisfy the concept std::ranges::range.

They both opt in to being a range the same way, via non-member functions:

directory_iterator begin(directory_iterator iter) noexcept;
directory_iterator end(const directory_iterator&) noexcept;

recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept;
recursive_directory_iterator end(const recursive_directory_iterator&) noexcept;

This is good enough for a range-based for statement, but for the range concept, non-member end is looked up in a context that includes ([range.access.end]/2.6) the declarations:

void end(auto&) = delete;
void end(const auto&) = delete;

Which means that non-const directory_iterator and non-const recursive_directory_iterator, the void end(auto&) overload ends up being a better match and thus the CPO ranges::end doesn't find a candidate. Which means that {recursive_,}directory_iterator is not a range, even though const {recursive_,}directory_iterator is a range.

This could be fixed by having the non-member end for both of these types just take by value (as libstdc++ currently does anyway) or by adding member functions begin() const and end() const.

A broader direction would be to consider removing the poison pill overloads. Their motivation from P0970 was to support what are now called borrowed ranges — but that design now is based on specializing a variable template instead of providing a non-member begin that takes an rvalue, so the initial motivation simply no longer exists. And, in this particular case, causes harm.

Date User Action Args
2020-09-06 13:07:36adminsetmessages: + msg11473
2020-08-27 00:00:00admincreate