通过模板运算符重载将std :: complex <t>乘以两倍

时间:2018-10-30 16:09:50

标签: c++ templates operator-overloading std operator-keyword

假设要定义std::complex<T>,我想将doubleT operator*(const T &t, double d)进行多重播放。由于我需要针对3种不同的类型T执行此操作,因此我尝试为操作员编写模板函数。这是T=float的示例。

#include <iostream>
#include <complex>

template <typename T>
std::complex<T> operator*(const std::complex<T> &cd, double d) {
    return std::complex<T>(cd.real() * d, cd.imag());
}

int main() {
    std::complex<float> cf(1.0, 1.0);
    std::complex<double> cd(1.0, 1.0);
    double d = 2.0;

    std::cout << cf * d << std::endl;
    std::cout << cd * d << std::endl;
}

这会导致编译器错误

error: ambiguous overload for ‘operator*’ (operand types are ‘std::complex<double>’ and ‘double’)

原因很清楚,因为对于T=double,我的重载与<complex>中的实现冲突。首先不建议将右侧强制转换为T(即上面示例中的cf * float(d)),因为这会给我的某些数据类型带来大量开销。

有什么办法可以告诉编译器它应该忽略T=double的重载吗?

2 个答案:

答案 0 :(得分:1)

std::complex已经定义了{p>形式的operator *

template< class T >
std::complex<T> operator*( const std::complex<T>& lhs, const T& rhs);

这与您自己的operator *冲突,因为这两个函数都决定采用std::complex<double>double

这意味着您实际上只需要为operator *std::vector<float>定义一个double,就可以将重载更改为

std::complex<float> operator*(const std::complex<float> &cd, double d) {
    return std::complex<float>(cd.real() * d, cd.imag());
}

然后

std::cout << cf * d << std::endl;
std::cout << cd * d << std::endl;

将起作用。

如果要保留模板函数的重载,则可以使用

使用SFINAE使其不适用于std::complex<double>情况下的编译。
template <typename T, std::enable_if_t<!std::is_same_v<double, T>, bool> = true>
std::complex<T> operator*(const std::complex<T> &cd, double d) {
    return std::complex<T>(cd.real() * d, cd.imag());
}

答案 1 :(得分:1)

  

有什么办法可以告诉编译器它应该忽略T = double的重载吗?

您可以使用SFINAE:

template <typename T>
std::enable_if_t<!std::is_same<double, T>::value, std::complex<T>>
operator*(const std::complex<T> &cd, double d) {
    return std::complex<T>(cd.real() * d, cd.imag());
}

但是您的实现与常规operator*不一致。

一种更安全的方法是引入您自己的类型来包装double,例如:

struct MyWrapper { double d; };

template <typename T>
std::complex<T> operator*(const std::complex<T> &cd, MyWrapper d) {
    return std::complex<T>(cd.real() * d.d, cd.imag());
}