With recent OS upgrade I noticed that small part of my code stopped compiling - it seems the reason is switching from g++-8
to g++-9
.
This code is compiling alright on g++ 8.3.0
(verified this using gcc:8.3
image from Dockerhub)
#include <filesystem>
#include <chrono>
int main() {
namespace fs = std::filesystem;
using namespace std::chrono_literals;
std::filesystem::last_write_time("test", std::chrono::system_clock::now() - 5min);
}
On g++ 9.1.0
it fails with:
test.cpp: In function 'int main()':
test.cpp:8:69: error: no matching function for call to 'last_write_time(const char [5], std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long int, std::ratio<1, 1000000000> > >)'
8 | fs::last_write_time("test", std::chrono::system_clock::now() - 5min);
| ^
In file included from /usr/local/include/c++/9.1.0/filesystem:39,
from test.cpp:1:
/usr/local/include/c++/9.1.0/bits/fs_ops.h:243:19: note: candidate: 'std::filesystem::file_time_type std::filesystem::last_write_time(const std::filesystem::__cxx11::path&)'
243 | file_time_type last_write_time(const path& __p);
| ^~~~~~~~~~~~~~~
/usr/local/include/c++/9.1.0/bits/fs_ops.h:243:19: note: candidate expects 1 argument, 2 provided
/usr/local/include/c++/9.1.0/bits/fs_ops.h:244:19: note: candidate: 'std::filesystem::file_time_type std::filesystem::last_write_time(const std::filesystem::__cxx11::path&, std::error_code&)'
244 | file_time_type last_write_time(const path& __p, error_code& __ec) noexcept;
| ^~~~~~~~~~~~~~~
In file included from /usr/local/include/c++/9.1.0/filesystem:36,
from test.cpp:1:
/usr/local/include/c++/9.1.0/bits/fs_fwd.h:362:47: note: no known conversion for argument 2 from 'std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long int, std::ratio<1, 1000000000> > >' to 'std::error_code&'
362 | file_time_type last_write_time(const path&, error_code&) noexcept;
| ^~~~~~~~~~~
In file included from /usr/local/include/c++/9.1.0/filesystem:39,
from test.cpp:1:
/usr/local/include/c++/9.1.0/bits/fs_ops.h:245:8: note: candidate: 'void std::filesystem::last_write_time(const std::filesystem::__cxx11::path&, std::filesystem::file_time_type)'
245 | void last_write_time(const path& __p, file_time_type __new_time);
| ^~~~~~~~~~~~~~~
/usr/local/include/c++/9.1.0/bits/fs_ops.h:245:56: note: no known conversion for argument 2 from 'time_point<std::chrono::_V2::system_clock,[...]>' to 'time_point<std::filesystem::__file_clock,[...]>'
245 | void last_write_time(const path& __p, file_time_type __new_time);
| ~~~~~~~~~~~~~~~^~~~~~~~~~
/usr/local/include/c++/9.1.0/bits/fs_ops.h:246:8: note: candidate: 'void std::filesystem::last_write_time(const std::filesystem::__cxx11::path&, std::filesystem::file_time_type, std::error_code&)'
246 | void last_write_time(const path& __p, file_time_type __new_time,
| ^~~~~~~~~~~~~~~
/usr/local/include/c++/9.1.0/bits/fs_ops.h:246:8: note: candidate expects 3 arguments, 2 provided
shell returned 1
Press ENTER or type command to continue
Compile command: g++ -std=c++17 test.cpp -lstdc++-fs
(even though linking stdc++-fs
is unnecessary on since g++9
)
My question is - what is the idiomatic use of this function the way I intended? Namely changing the last write time of a file to five minutes ago.
I understand I used this in somehow non-idiomatic way if a breaking change was introduced.
As pointed out by @LightnessRacesinOrbit in their answer the std::filesystem::file_time_type
that last_write_time
takes uses an unspecified time_point
type. This means it is completely legal for this to break moving from one compiler to another or even versions of the same compiler.
What you can do though is get the clock that the implementation uses, and use that yourself. std::chrono::time_point
was built to take the clock type that creates it as a template parameter, and it surfaces a public clock
type that represents that. So to portably get the clock, and call now
on it you can use
std::filesystem::last_write_time("test", std::filesystem::file_time_type::clock::now() - 5min);
// ^ give me whatever clock you use and call now on it
This is touched on by cppreference.com's example.
Your giving a std::chrono::time_point<std::chrono::system_clock>
to std::file_time_type
was never portable; it just happened to work on your previous toolchain. That wasn't really your fault: you were unavoidably relying on implementation details.
C++20 has introduced a portable alternative, so you'd do:
std::filesystem::last_write_time("test", std::chrono::file_clock::now() - 5min);
// ^^^^^^^^^^
… i.e. use file_clock
, rather than just hoping that the alternative is convertible to whatever implementation-defined clock is used by your toolchain.
Whether that's supported in GCC 9 I couldn't say for sure, though it doesn't look like it. If there's a workaround, I'm not aware of one (which is why the C++20 change was made).
This problem affects other people on other toolchains, too.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With