接受子类的模板作为对象的模板

Accept Template of Child Class as Template for Object

本文关键字:对象 子类      更新时间:2023-10-16

在Bellow示例中,使用STD :: Chrono库,我正在寻找一种接受基本计时器的持续时间的方法。

template <std::chrono::duration D> //Accept either std::chrono::minute, second, etc...
class myTimer{

}

但是,由于持续时间不符合模板关键字的标准。

template <class T>
class myTimer{
   //I could do a static cast, but Duration is only a template used by the children, not an actual class per say. 
}

因此,我的问题归结为,最好的解决方案对于更少的代码和更好的可用性是什么?我觉得自己是一个静态的演员,与模板中的一个未知的孩子无法正常工作,但我可能完全错了。

您在这里有很多选择,范围从易于且易于畅通,到极其富裕但多重的工作。

最简单的是仅存储nanoseconds,而不是模板myTimer

class myTimer
{
    std::chrono::nanoseconds time_;
    ...
};

您的构造函数只能采用nanoseconds。所有"内置"计时单元将隐式转换为nanoseconds

myTimer t{3min};  // ok, 180'000'000'000ns

这里唯一的缺点是,每个每个 duration都会隐式转换为nanoseconds。也许您希望您的客户能够使用picseconds,1/60s单元或浮点持续时间,或者这里的意图(很难说)是控制计时器内部存储的精度(不是真正必要的,但是你永远不会知道)。然后您可能会移动到模板的解决方案:

is_duration模板开始并不是一个不好的起点。即使您最终不在此项目中使用它,它也可能方便:

template <class T>
struct is_duration
    : public std::false_type
    {};
template <class Rep, class Period>
struct is_duration<std::chrono::duration<Rep, Period>>
    : public std::true_type
    {};

现在您可以说is_duration<T>{},这是一个编译时布尔,可以回答false的正确。您可以(例如)这样使用它:

template <class D,
          class = std::enable_if_t<is_duration<D>{}>>
class myTimer
{
    D time_;
};

这将使除std::chrono::duration以外的任何其他内容都无法编译。

您也可以采用不需要is_duration的方法:

template <class D> class myTimer;
template <class Rep, class Period>
class myTimer<std::chrono::duration<Rep, Period>>
{
};

如果有兴趣探索这条路线,请尝试这两种方式并确定您最喜欢的错误消息。

不要忘记:最适合您的解决方案可能是最简单的:只需使用 nanoseconds,然后将所有内容都在此上。