首页 > 解决方案 > C++ 模板 - 为复数和复数泛化标量积矢量图

问题描述

我正在尝试重载*运算符以使用模板计算标量积vector<double>vector<complex<double>>向量,并且在尝试了我所知道的一切之后我到达了这个:

#include <iostream>
#include <complex>
#include <vector>
using namespace std;

template<typename T> T operator* (const vector<T> &a, const vector<T> &b) {
    T retvar; complex<double> c = 0;
    for (int i = 0; i < b.size(); i++) c += conj(a[i])*b[i];
    if (is_same<T, double>::value) retvar = c.real();
    else                           retvar = c;  // (*) the error is generated by this line
    return retvar;
}

int main() {
    vector<double> a, b;
    a.push_back(5); b.push_back(3);
    cout << a*b << endl;
    return 0;
}

我想要做的是:我计算复数的标量积,然后我将它返回包含在模板给出的类型的变量中,以避免任何奇怪的转换。但是,g++ 在 (*) 行抛出以下错误:

error: assigning to 'double' from incompatible type 'complex<double>'

老实说,我已经没有想法了,有什么好方法可以摆脱这种情况而不会使操作员两次超载

标签: c++templatesvectordoublecomplex-numbers

解决方案


不要重载您不拥有的类型的运算符。相反,你可以写一个

template <typename T>
struct my_vect {
    std::vector<T> data;
    T operator* (const my_vect<T>& other);
};

接下来,std::conj无论参数的类型是什么,都返回一个复数。在我看来,这是不幸的,因为在数学中,复向量和非复向量的标量积没有区别。实数的共轭是实数。要恢复这个不错的属性,可以使用my_conj

template <typename T> struct is_complex : std::false_type {};
template <typename T> struct is_complex<std::complex<T>> :std::true_type {};


template <typename T>
T my_conj(const T&t) {
    if constexpr (is_complex<T>::value) return std::conj(t);
    else return t;
}

现在,对于复数和非复数向量,标量积的定义可以相同。完整示例:

#include <vector>
#include <complex>
#include <iostream>
#include <type_traits>

template <typename T> struct is_complex : std::false_type {};
template <typename T> struct is_complex<std::complex<T>> :std::true_type {};


template <typename T>
T my_conj(const T&t) {
    if constexpr (is_complex<T>::value) return std::conj(t);
    else return t;
}


template <typename T>
struct my_vect {
    std::vector<T> data;
    T operator* (const my_vect<T>& other) {
        T result;
        for (size_t i = 0; i < data.size(); i++) result += my_conj(data[i])*other.data[i];
        return result;
    }
};

int main() {
   my_vect<double> x{{1,2,3}};
   std::cout << x*x << '\n';
   my_vect<std::complex<double>> y{{ {1,2} }};
   std::cout << y*y;
}

PS:您应该检查两个向量的大小是否相同。


推荐阅读