【问题标题】:C++ templates - generalize scalar product for double and complex<double> vectorsC++ 模板 - 泛化 double 和 complex<double> 向量的标量积
【发布时间】:2020-03-16 19:08:55
【问题描述】:

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

#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>'

老实说,我已经没有想法了,有什么好的方法可以摆脱这个而不会使运算符重载两次

【问题讨论】:

  • 我相信使用auto 和/或尾随返回类型是您应该调查的内容。
  • 双精度和复数的标量积不一样吗?我的意思是除了一个是另一个复杂的两倍之外?
  • 不要重载你不拥有的类型的操作。如果您愿意,请将向量包装在您自己的类中并为它们提供重载。
  • 同意@NathanOliver。使用显式命名的函数 - scalar_product
  • 你用的是c++17吗?然后使用if constexpr (is_same...)

标签: c++ templates vector double complex-numbers


【解决方案1】:

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

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:你应该检查两个向量的大小是否相同。

【讨论】:

  • 谢谢你,我想它会起作用,但是在你回答前几分钟,已经有人发表评论实际上解决了所有问题..
  • @marco 我看到了评论,但单独的is_same 只会让您检查double,而检查complex 的专业化适用于任何复杂或不复杂的东西
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-15
  • 2011-06-14
  • 1970-01-01
  • 2011-09-17
相关资源
最近更新 更多