如何将 `duration_cast` 用于派生的 class?

How to use `duration_cast` for a derived class?

我正在使用 std::chrono 清理我的计时器 class。除了我似乎无法将 duration_cast 应用于派生的 classes 之外,其他一切都很顺利。嗯,我让它以不同的方式工作,但我仍然想知道我错过了什么。

有关错误消息,请参阅 here

#include <iostream>
#include <chrono>

typedef std::chrono::high_resolution_clock Clock;

class Milliseconds : public std::chrono::milliseconds
{
public:
    typedef std::chrono::milliseconds Base;
    typedef Base::rep Type;

    using Base::Base;
};

inline Milliseconds::Type millisecondsSinceEpoch()
{
    return std::chrono::duration_cast<Milliseconds::Base>(Clock::now().time_since_epoch()).count();
    //duration_cast<Milliseconds> ERROR!
}

int main() {
    using namespace std;
    cout << millisecondsSinceEpoch() << endl;
    return 0;
}

Visual C++ 2015 RC 在代码中替换 duration_cast<Milliseconds> 时出现以下错误:

error C2770: invalid explicit template argument(s) for 'enable_if<std::chrono::_Is_duration<_Ty>::value,_To>::type std::chrono::duration_cast(const std::chrono::duration<_Rep,_Period> &)'

std::chrono::_Is_duration<_Ty> trait 是 MSVC 中使用的标准库的内部实现细节;它的存在是为了让事情按照标准工作并使错误消息更容易理解:你需要给 duration_cast 一个模板参数,它实际上是 std::chrono::duration 模板的特化。在这种情况下不考虑派生到基础的关系。

[20.12.5.7]在标准(N4431草案)中有如下描述:

template <class ToDuration, class Rep, class Period>
  constexpr ToDuration duration_cast(const duration<Rep, Period>& d);

Remarks: This function shall not participate in overload resolution unless ToDuration is an instantiation of duration.


Base class 模板特化在从函数调用 [14.8.2.1] 的参数类型推导模板参数时被考虑,但在将参数匹配到 class 模板部分特化 [ 14.5.5.1],这就是 _Is_duration 特征所发生的情况。

标准duration_cast只能用于转换为duration的特化。 [time.duration.cast]/p1:

template <class ToDuration, class Rep, class Period>
constexpr ToDuration duration_cast(const duration<Rep, Period>& d);

Remarks: This function shall not participate in overload resolution unless ToDuration is an instantiation of duration.

如果 ToDuration 不是 duration 的特化,则签名从重载决议中删除(通过 SFINAE 或类似技术),调用失败,除非另一个函数模板调用 duration_cast可用。

您需要提供自己的 duration_cast

template< typename my_dest, typename my_source >
my_dest duration_cast( my_source const & value )
    { return duration_cast< my_dest::duration >( value ); }

不允许将此放在 namespace std::chrono 中,因此您不能将其称为 std::chrono::duration_cast。一种替代方法是将 using std::chrono::duration_castusing my_namespace::duration_cast 添加到您的名称空间,并用它来限定调用。 (在示例中,您没有使用名称空间,因此只需要 using std…。)