【问题标题】:Class that stores a std::chrono::duration as a member?将 std::chrono::duration 存储为成员的类?
【发布时间】:2016-04-28 00:24:43
【问题描述】:

我想创建一个类,它的构造接受std::chrono::duration 参数并将结果存储在一个成员中,以便我以后可以将它传递给std::this_thread::sleep_for()

我知道我可以编写一些类似sleep_for 的函数模板,如下所示:

template <typename Rep, typename Period>
void mySleep( std::chrono::duration<Rep, Period> time )
{
  std::this_thread::sleep_for(time);
}

这可能是一个类的成员函数。但是下面的情况呢?

class UsesDuration
{
public:
   template <typename Rep, typename Period>
   UsesDuration( std::chrono::duration<Rep, Period> dur ) :
      my_duration(dur) { }

   void doSomethingPeriodic()
   {
       while( some_condition )
       {
          std::this_thread::sleep_for(my_duration);
          somethingInteresting();
       }
   }    

private:
   ???  my_duration;   /* How do I declare this??? */
}

是否有一种干净的方法来保持“抽象”持续时间 A)理想情况下不将整个类转换为模板类,B)通过将类转换为类模板?

【问题讨论】:

  • 这是过于复杂的std::chrono引入的问题之一;我第一次看到这个东西我以为是个笑话。带有两个参数(其中一个与编译时间有理算术有关)的模板只是为了表示持续时间,这纯粹是疯狂。只需使用double 来存储秒数,就像任何其他理智的语言一样,忘记所有这些人为的非问题,sleep_for 的分辨率比double 的分辨率要差得多。
  • 为什么不使用其中一种帮助器类型,例如 std::chrono::milliseconds,具体取决于所需的粒度?
  • 我确实喜欢在秒、纳秒等之间转换的能力。如果你只坚持预定义的类型,你甚至会忘记它是一个可怕的模板。
  • @MatteoItalia:恕我直言,您根本不明白您在说什么。在传播有关它的错误信息之前,请花时间学习它。
  • @MatteoItalia C++ 与其他编程语言有不同的目标,因此显然 C++ 将针对同一问题有不同的解决方案。不使用 double 的原因很简单:没有人愿意使用浮点运算来跟踪性能受限系统的时间。在放弃解决方案之前,您应该了解目标。

标签: c++ c++11 chrono


【解决方案1】:

一个更简单的解决方案是使用std::chrono::duration,它与您想要的一样好或更好:

#include <chrono>
#include <thread>

class UsesDuration
{
public:
   UsesDuration( std::chrono::nanoseconds dur ) :
      my_duration(dur) { }

   void doSomethingPeriodic()
   {
       while( some_condition )
       {
          std::this_thread::sleep_for(my_duration);
          somethingInteresting();
       }
   }

   void somethingInteresting();

private:
   std::chrono::nanoseconds  my_duration;
};

int
main()
{
    using namespace std::chrono_literals;
    UsesDuration x{5min};
}

没有必要对所有内容都进行模板化,除非您确实想要这种通用性。您所有的预定义单位都隐式转换为nanoseconds。如果您遇到客户端发送的内容无法完全转换为nanoseconds的状态,您会在编译时发现,然后然后可以决定是否要模板化,或者使用其他解决方案。

另一种比存储double 更好的解决方案是存储双基持续时间:

#include <chrono>
#include <thread>

class UsesDuration
{
public:
   UsesDuration( std::chrono::duration<double> dur ) :
      my_duration(dur) { }

   void doSomethingPeriodic()
   {
       while( some_condition )
       {
          std::this_thread::sleep_for(my_duration);
          somethingInteresting();
       }
   }

   void somethingInteresting();

private:
   std::chrono::duration<double>  my_duration;
};

int
main()
{
    using namespace std::chrono_literals;
    UsesDuration x{5min};
}

Every chrono::duration 将隐式转换为浮点持续时间。在此示例中,我选择秒作为精度,并选择双倍作为表示。你可以选择任何你想要的(长双精度和微秒,等等)。

这里有很多选择。所有这些都为您提供了纯 double 无法提供的类型安全性,并且不会牺牲性能和灵活性。

只需使用 double 来存储秒数

是你能得到的最糟糕的建议。 学习 &lt;chrono&gt;。它具有很大的灵活性,并且有很多不需要模板。


我坚持要你学习&lt;chrono&gt;而不给你一些指导可能是不礼貌的。

Nicolai M. Josuttis' "The C++ Standard Library - A Tutorial and Reference, 2nd Edition"&lt;chrono&gt; 有很好的介绍。仅这一章就可以支付本书的费用。确保您获得第 2 版。他的第一版涵盖了没有&lt;chrono&gt; 的C++03。披露:尽管他是我的朋友,但我没有安排(财务或其他方面)宣传 Nico 的书。

对于那些愿意深入研究委员会文件的人,&lt;chrono&gt; 提案在这里:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2661.htm

duration 部分(链接在内容中)是我建议你开始的地方,如果你不耐烦的话。它读起来更像是一篇教程,而不是一篇技术论文,因为我试图让委员会自己跟上进度。它包括我在上面的回答中给出的建议等等。

这是一个视频介绍教程:

https://www.youtube.com/watch?v=P32hvk8b13M

【讨论】:

  • 有没有办法让 my_duration 成为静态常量?我尝试了很多东西,最后得到了我的 clang 和 mingw53(我使用的是 qt 5.8)没有抱怨的东西: constexpr static std::chrono::milliseconds every_duration {10000ms};但随后在构造函数 O_o 中未定义符号 every_duration
  • @d.Candela:是的,除了你已经拥有的之外,把constexpr std::chrono::milliseconds UsesDuration::every_duration;放在类定义的.cpp 中。您也可以使用10s 进行初始化,以使您的初始化更具可读性。
【解决方案2】:

我可以看到的一个解决方案是在你的类中使用特定的持续时间,然后你可以使用std::chrono::duration_cast 将提供给构造函数的类型转换为你用作类成员的类型。这使您可以不模板化课程,但仍然可以采用任何类型的持续时间

template <typename Rep, typename Period>
   UsesDuration( std::chrono::duration<Rep, Period> dur ) :
      my_duration(std::chrono::duration_cast<decltype(my_duration)>(dur)) { }

【讨论】:

  • 这大概就是我要做的。或者按照 Matteo 的建议去存储一个 double。
  • 我宁愿存储一个实际提到它代表什么的类型,而不是一个双精度型,它可以是任何东西(毫秒?秒?)。标准类型还阻止您将秒传递给需要 ms 的函数,并允许您轻松地在它们之间进行转换。如果您忘记了它们下面是可怕的模板,它们实际上非常好
  • 更好的是,做template&lt;typename Duration&gt; UsesDuration(Duration d) : my_duration(duration_cast&lt;decltype(my_duration)&gt;(d)) {}
  • @JoelCornett 我添加了decltype 部分。仍然习惯使用它。我对更改模板类型犹豫不决,因为那是 OP 所拥有的,但这是一个很好的建议。我想知道如果通过了非持续时间,哪种方式会给出更好的错误消息。
  • @dgel 它不会阻止您将秒数转换为期望毫秒数 - 它会自动转换它。
猜你喜欢
  • 2016-07-20
  • 1970-01-01
  • 1970-01-01
  • 2013-07-27
  • 1970-01-01
  • 2018-02-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多