用户定义的重载运算符*,带有std :: chrono :: duration [英] User-defined overloaded operator * with std::chrono::duration

查看:118
本文介绍了用户定义的重载运算符*,带有std :: chrono :: duration的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个频率类模板,旨在与 std :: chrono结合使用:: duration .频率对象每单位持续时间存储多个周期(两者均使用模板参数作为其类型).这个想法是,将Frequency乘以持续时间会生成Rep类型的对象,这是类的定义.除了相关成员外,我已经省略了所有其他成员.

I've created a Frequency class template intended to work in conjunction with std::chrono::duration. A Frequency object stores a number of cycles per unit duration (both using template parameters for their types). The idea is that multiplying a Frequency by a duration produces an object of type Rep. Here's the class definition. I've omitted all but the relevant members.

#include <ratio>
#include <chrono>
using namespace std::chrono;

template <typename Rep, typename Period = std::ratio<1>>
class Frequency
{
public:
    explicit Frequency(Rep cycles) : _cycles{cycles} { }

    friend Rep operator *(const Frequency<Rep, Period>& f, const duration<Rep, Period> d)
    {
        return f._cycles * d.count();
    }
    friend Rep operator *(const duration<Rep, Period> d, const Frequency<Rep, Period>& f)
    {
        return f._cycles * d.count();
    }
private:
    Rep _cycles; ///> The number of cycles per period.
};

问题(我认为)是std :: chrono :: duration也重载了*运算符,如下所示:

The problem (I think) is that std::chrono::duration also overloads the * operator, as follows:

template< class Rep1, class Period, class Rep2 >
duration<typename std::common_type<Rep1,Rep2>::type, Period>
    constexpr operator*( const duration<Rep1,Period>& d,
                         const Rep2& s );

template< class Rep1, class Rep2, class Period >
duration<typename std::common_type<Rep1,Rep2>::type, Period>
    constexpr operator*( const Rep1& s,
                         const duration<Rep2,Period>& d );

根据 cppreference ,每种方法都

将持续时间d转换为rep是Rep1和Rep2之间的常见类型,并将转换后的滴答数乘以s.

Converts the duration d to one whose rep is the common type between Rep1 and Rep2, and multiplies the number of ticks after conversion by s.

我相信编译器正在尝试使用这些重载的运算符模板,而不是我的重载.当我编写以下代码时:

I believe that the compiler is trying to use these overloaded operator templates instead of my overloads. When I write the following code:

Frequency<double> f{60.0};
duration<double> d{1.0};
double foo = f * d;

我在VS2013中收到类似以下错误的信息:

I get something like the following error in VS2013:

C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\INCLUDE\type_traits(1446) : error C2446: ':' : no conversion from 'double' to 'Frequency<double,std::ratio<0x01,0x01>>'
        Constructor for class 'Frequency<double,std::ratio<0x01,0x01>>' is declared 'explicit'
        source_file.cpp(27) : see reference to class template instantiation 'std::common_type<Frequency<double,std::ratio<0x01,0x01>>,Rep>' being compiled
        with
        [
            Rep=double
        ]

第1446行是std::common_type的VS实现.

And line 1446 is the VS implementation of std::common_type.

那么,有没有一种方法可以确保调用我的重载而不是std :: chrono :: duration中的重载?我知道我可以通过不使用运算符重载而不是编写一个命名不同的方法来解决该问题,但我想尽可能地了解这里发生的事情. (此外,重载更加方便.)

So, is there a way to ensure that my overloads get called instead of those in std::chrono::duration? I know that I could solve the problem by not using operator overloading and writing a differently named method instead, but I'd like to get a better understanding of what's going on here if possible. (Plus the overloads are more convenient.)

此外,对于这个问题是否重复,我深表歉意,但搜索后找不到类似的内容.

Also, I apologize if this question is a duplicate, but I was unable to find anything similar after searching.

推荐答案

在此代码中:

Frequency<double> f{60.0};
duration<double> d{1.0};
double foo = f * d;

编译器说:哦,我必须找到一个包含Frequency<double>std::chrono::duration<double>operator*.那里有什么operator*可能性?它会生成一个可能性列表,主要由这两个组成:

The compiler says "oh, I have to find an operator* that takes a Frequency<double> and a std::chrono::duration<double>. What operator* possibilities are there? And it generates a list of possibilities, composed mostly of these two:

friend Rep operator *(const Frequency<Rep, Period>& f, const duration<Rep, Period> d)
{
    return f._cycles * d.count();
}

template< class Rep1, class Rep2, class Period >
duration<typename std::common_type<Rep1,Rep2>::type, Period>
constexpr operator*( const Rep1& s,
                     const duration<Rep2,Period>& d );

然后,它尝试准确找出 每个签名是什么.第一个是:

Then, it tries to figure out exactly what each of the signatures are. The first one is:

Rep operator *(const Frequency<Rep, Period>& f, const duration<Rep, Period> d)

并尝试第二个结果:

error C2446: ':' : no conversion from 'double' to 'Frequency<double,std::ratio<0x01,0x01>>'
        Constructor for class 'Frequency<double,std::ratio<0x01,0x01>>' is declared 'explicit'
        source_file.cpp(27) : see reference to class template instantiation 'std::common_type<Frequency<double,std::ratio<0x01,0x01>>,Rep>' being compiled

由于它甚至无法弄清楚签名是什么,因此无法弄清楚要选择哪个签名,于是放弃了.在这种情况下,我会认为这是MSVC operator*实现中的错误.

Since it can't even figure out what the signature is, it can't figure out which one to select, and it gives up. I would consider this a bug in MSVC's implementation of operator* in this case.

一个明显的解决方法是使common_type<Frequency<double>,Rep>能够编译,可能是通过删除构造函数上的explicit限制. aschepler 发现,代替专门研究common_type:

The obvious workaround is to make common_type<Frequency<double>,Rep> able to compile, possibly by removing the explicit limitation on the constructor. aschepler observes it might be smarter and more useful to instead specialize common_type:

namespace std {
    template <typename Rep, typename Period>
    struct common_type<Frequency<Rep,Period>, std::chrono::duration<Rep,Period>>   
    {
        typedef Rep type;
    };
    template <typename Rep, typename Period>
    struct common_type<std::chrono::duration<Rep,Period>, Frequency<Rep,Period>>   
    {
        typedef Rep type;
    };
}

这篇关于用户定义的重载运算符*,带有std :: chrono :: duration的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆