【问题标题】:How to make older versions of clang happy with atomic's default exception specification如何让旧版本的 clang 对 atomic 的默认异常规范感到满意
【发布时间】:2021-03-29 22:58:49
【问题描述】:

我有一个类,它有一个将 std time_point 包装在原子中的成员变量。我很难让较旧的编译器对此感到满意。我最初在接受 10 之前的 GCC 版本时遇到了问题。我通过显式初始化解决了这个问题。

我认为这让所有编译器都很高兴。但是,一旦我的代码投入生产,我在使用较旧的 clang 编译器的更彻底的 CI(与 PR CI 相比)中遇到了一个问题。该项目是 Apache Traffic Server,所以它是开源的,如果查看它是有趣的。代码如下:

https://github.com/apache/trafficserver/blob/master/include/tscore/Throttler.h#L117

这是一个演示问题的最小示例:

#include <atomic>
#include <chrono>

struct A {
  A() {}

  using Clock = std::chrono::system_clock;
  using TimePoint = Clock::time_point;

  // The explicit initialization is needed by
  // GCC earlier than 10.
  std::atomic<TimePoint> _last_allowed_time{TimePoint{}};
};

错误可以在godbolt中重现: https://godbolt.org/z/4db4osf66

这是错误:

In file included from <source>:1:
/opt/compiler-explorer/gcc-8.3.0/lib/gcc/x86_64-linux-gnu/8.3.0/../../../../include/c++/8.3.0/atomic:194:7: error: exception specification of explicitly defaulted default constructor does not match the calculated one
      atomic() noexcept = default;
      ^
<source>:12:26: note: in instantiation of template class 'std::atomic<std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long, std::ratio<1, 1000000000> > > >' requested here
  std::atomic<TimePoint> _last_allowed_time{TimePoint{}};
                         ^
1 error generated.
Compiler returned: 1

使用 Godbolt 配置,任何比 clang 9 更新的东西都不会引发此错误。我想我可以 ifdef 解决它,但我不确定如果我这样做的解决方法是什么。显式初始化让 gcc 很高兴。我该怎么做才能让 clang 8 及更早版本对这种结构感到满意?


顺便说一下,这个问题与以下内容有关: Program with "noexcept" constructor accepted by gcc, rejected by clang

虽然该问题讨论了 clang 或 gcc 对于错误或没有错误是否正确,但我并不关心编译器在理论上做什么是正确的。在以后的版本中,clang 和 gcc 似乎都同意这在形成时是可以的。这很好,但对于需要支持旧编译器的项目没有帮助。我的问题是问我可以做些什么来让旧的编译器满意。

【问题讨论】:

  • std::atomic&lt;TimePoint&gt; _last_allowed_time(TimePoint()); seems to work(从 Clang 5.0.0 开始)。
  • A()=default 修复了吗?
  • @PaulSanders 这行得通。谢谢你。好,易于。如果您将其发布为答案,我会接受。
  • @PaulSanders:实际上,它可以编译,但我认为它做的事情与我们预期的不同。在使用该“变量”时,它现在表示它被解释为“非静态成员函数”。所以我认为该行被解释为一个函数而不是一个成员变量。
  • @MooingDuck:不,这不能解决问题。

标签: c++ gcc clang


【解决方案1】:

作为一种解决方法,您可以将 TimePoint 设为子类(使用 noexcept 默认构造函数)而不是 typedef。

#include <atomic>
#include <chrono>

struct A {
  A() {}

  using Clock = std::chrono::system_clock;
  class TimePoint : public Clock::time_point {
  public:
    using time_point::time_point;
    constexpr TimePoint() noexcept : time_point() {}
  };

  std::atomic<TimePoint> last_allowed_time_;
};

这会在 Godbolt 上为所有 GCC ≥4.8.1 和 clang ≥3.4.1 编译(使用 -std=c++1y)。

编辑:另外,请注意,以下划线开头的标识符是为实现保留的。我喜欢使用尾随下划线(即last_allowed_time_ 而不是_last_allowed_time)。

【讨论】:

  • 这很有效:它为各种编译器构建并通过单元测试。谢谢你的回答。
猜你喜欢
  • 1970-01-01
  • 2017-08-12
  • 1970-01-01
  • 2011-09-26
  • 1970-01-01
  • 1970-01-01
  • 2012-12-20
  • 1970-01-01
  • 2013-08-04
相关资源
最近更新 更多