Given this minimal code example in which I construct a time_point from std::chrono::nanoseconds:
#include <chrono>
int
main()
{
std::chrono::time_point<std::chrono::system_clock> t{std::chrono::nanoseconds{10}};
(void)t;
}
As I read things, this should be fine per specification: nanoseconds is a duration and time_point supports construction from a duration. Indeed, this compiles fine using x86_64 clang 11.0.0:
However, on my Mac when I compile this I receive the following error:
clang++ -g -Wall -Werror -std=c++17 test.cc -o test
test.cc:6:54: error: no matching constructor for initialization of 'std::chrono::time_point<std::chrono::system_clock>'
std::chrono::time_point<std::chrono::system_clock> t{std::chrono::nanoseconds{10}};
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/chrono:1355:28: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'std::chrono::nanoseconds' (aka 'duration<long long, ratio<1LL, 1000000000LL> >') to
'const std::__1::chrono::time_point<std::__1::chrono::system_clock, std::__1::chrono::duration<long long, std::__1::ratio<1, 1000000> > >' for 1st argument
class _LIBCPP_TEMPLATE_VIS time_point
^
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/chrono:1355:28: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'std::chrono::nanoseconds' (aka 'duration<long long, ratio<1LL, 1000000000LL> >') to
'std::__1::chrono::time_point<std::__1::chrono::system_clock, std::__1::chrono::duration<long long, std::__1::ratio<1, 1000000> > >' for 1st argument
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/chrono:1369:70: note: candidate constructor not viable: no known conversion from 'duration<[...], ratio<[...], 1000000000>>' to 'const duration<[...], ratio<[...], 1000000>>' for 1st argument
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 explicit time_point(const duration& __d) : __d_(__d) {}
^
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/chrono:1374:5: note: candidate template ignored: could not match 'time_point' against 'duration'
time_point(const time_point<clock, _Duration2>& t,
^
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/chrono:1368:61: note: candidate constructor not viable: requires 0 arguments, but 1 was provided
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 time_point() : __d_(duration::zero()) {}
^
1 error generated.
Here's the clang I'm using:
$ clang++ --version
Apple clang version 12.0.0 (clang-1200.0.26.2)
Target: x86_64-apple-darwin19.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
Can someone help me understand whether I'm dealing with a compiler bug in the Apple clang compiler or whether I'm getting away with something in the x86_64 clang that isn't strictly supported?
Update
Howard's answer points out my problem and provides the solution. Just to make things explicit and maybe avoid confusing others, here's my initial question, quoted from above:
Can someone help me understand whether I'm dealing with a compiler bug in the Apple clang compiler or whether I'm getting away with something in the x86_64 clang that isn't strictly supported?
This question has "neither" as the correct answer. I initially wrote my code in libstd c++ on Linux which has nanoseconds as a default duration for time_point. I didn't realize it, but my code implicitly assumed that. And when I tried to build this same code constructing a time_point from a nanosecond duration in Apple clang, it failed to compile because time_point there defaults to microseconds. Thus the compiler warned me of the truncation, which is helpful and certainly not a compiler bug. Once I did as Howard suggested and explicitly instantiated all of my time_points with nanoseconds, I no longer have issues on either system.
On macOS, system_clock::duration
is microseconds
. The chrono library is keeping you from accidentally truncating nanoseconds
to microseconds
and losing information. You can either do the truncation manually (say with duration_cast
), or you can change the type of the time_point
such that it can store nanoseconds
:
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>
t{std::chrono::nanoseconds{10}};
In C++20 the above line can be simplified to:
std::chrono::sys_time t{std::chrono::nanoseconds{10}};
The type and value of t
will remain unchanged. sys_time
is just a type-alias for a time_point
based on system_clock
.