<T> 通过模板化运算符重载将 std::complex 乘以双倍

Multiplying a std::complex<T> by double via templated operator overload

本文关键字:std complex 重载 gt lt 运算符      更新时间:2023-10-16

假设定义了T operator*(const T &t, double d),我想将std::complex<T>乘以double。由于我需要对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的重载吗?

有什么方法可以告诉编译器,它应该忽略我的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());
}

但是您的实现与常规CCD_ 11不一致。

一种更安全的方法是引入您自己的类型来包装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());
}

std::complex已经以的形式定义了operator *

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

这与您自己的operator *冲突,因为这两个函数都解析为获取std::complex<double>double

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

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());
}