苹果的Clang编译器:为什么我不能从std::chrono::nanoseconds创建time_point?

3

考虑到这个最小代码示例,我从std::chrono::nanoseconds中构造了一个time_point:

#include <chrono>

int
main()
{
  std::chrono::time_point<std::chrono::system_clock> t{std::chrono::nanoseconds{10}};
  (void)t;
}

据我所知,按照规范,纳秒是一段时间,time_point支持从时长构造。实际上,在使用x86_64 clang 11.0.0编译时,这段代码可以成功编译:https://godbolt.org/z/jWWzTo。然而,在我的Mac上编译时,会收到以下错误提示:
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.

这是我正在使用的clang:

$ 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

有人能帮助我理解,我是在苹果clang编译器中遇到了编译器bug,还是在x86_64 clang中得以不严格支持的东西?
更新
Howard的答案指出了我的问题并提供了解决方案。为了使事情明确,也许避免让其他人感到困惑,以下是我最初的问题:
这个问题的正确答案是“两者都不是”。我最初在Linux上使用libstd c++编写了代码,其中纳秒是time_point的默认持续时间。我没有意识到这一点,但是我的代码隐式地假定了这一点。当我尝试在苹果clang中构建同样的代码,从纳秒持续时间构造time_point时,它无法编译,因为那里的time_point默认为微秒。因此,编译器警告我进行截断,这是有帮助的,肯定不是编译器的bug。一旦我按照Howard的建议明确地使用纳秒实例化所有我的time_points,我在任何系统上都不再有问题。
2个回答

4
在 macOS 上,system_clock::durationmicroseconds。chrono 库可以避免意外截断 nanosecondsmicroseconds 并丢失信息。你可以手动进行截断(例如使用 duration_cast),或者更改 time_point 的类型以存储 nanoseconds
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>
    t{std::chrono::nanoseconds{10}};

在C++20中,以上行可以简化为:
std::chrono::sys_time t{std::chrono::nanoseconds{10}};
t的类型和值将保持不变。sys_time只是一种基于system_clocktime_point的类型别名。

1

有两个构造函数可以接受一个时间段作为参数来创建time_point对象。

constexpr explicit time_point(const duration& d);
template<class Duration2>
  constexpr time_point(const time_point<clock, Duration2>& t);

第一个与时钟提供的时间相同。 第二个应该将持续时间转换为时钟提供的持续时间。
另外,如果我理解正确,您要求从纪元开始加上10纳秒。如果system_clock的分辨率大于10纳秒(确实如此),那么它应该被截断为零,您将得到一个等于纪元开始的time_point。
现在,关于为什么这不编译。第二个构造函数基于Duration2是否可转换为duration (也就是system_clock::duration)进行SFINAE。
对于libc++来说,似乎是错误的。即,这将失败:
static_assert (std::is_convertible<
                  std::chrono::nanoseconds,
                  std::chrono::system_clock::duration
                  >
                ::value, "");

问题就变成了-这个是否应该为false。
后来:Howard的答案已经让我相信在Mac OS上这应该是false。
如果您在Linux上使用libstdc ++,那么std :: chrono :: system_clock :: duration实际上是std :: chrono :: nanoseconds ,因此它使用第一个构造函数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接