简体   繁体   中英

C++ templates - generalize scalar product for double and complex<double> vectors

I am trying to overload the * operator for computing the scalar product for both vector<double> and vector<complex<double>> vectors using templates, and I arrived to this after trying everything I know:

#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;
}

What I am trying to do is: I compute the scalar product as for complex numbers, and then I return it contained in a variable which type is given by the template, to avoid any weird casting. However, g++ throws the following error at line (*):

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

I honestly ran out of ideas, what would be a good way to get out of this without overloading the operator twice ?

Dont overload operators of types you dont own. Instead you can write a

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

Next, std::conj returns a complex number, no matter what was the type of the argument. In my opinion this is unfortunate, because in maths there is no difference between the scalar product of complex vectors and non-complex vectors. The conjugate of a real number is a real number. To restore that nice property one can use a 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;
}

Now the definition of the scalar product can be the same for complex and non complex vectors. Complete example:

#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: You should check that the two vectors are of same size.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM