使用 std::complex<double> 将 int 转换为 double 以进行 `*` 操作
convert int to double for `*` operations with std::complex<double>
我是一名物理学家,试图尽量减少在用于计算的代码文件(方程式和函数)中键入类型转换和强制转换。计算通常涉及复数。因此,我将 complex<double>
类型扩展为 cd
以实现紧凑并添加了一些帮助方法。
class cd: public complex<double> { ... }
扩展而不是仅仅使用 typedef
的原因是物理符号 (string
) 和物理单位 (string
) 可以与物理变量一起存储。
现在如果在计算中我有像
这样的实例
int i = 2;
cd z(1,2);
cout << i*z;
这会出错,因为没有运算符可以将 int
和 cd
相乘。 (说实话,我认为 C++ 会自动将 int
隐式转换为 double
并使用相关的运算符。)在手动定义这样的运算符后
cd operator*(const int& i, const cd& z)
{
return cd(i*z.real(),i*z.imag());
}
c++ 然后警告像
这样的部分类型转换的歧义
double x = 30;
x*z;
下面的x
是double,I
是cd
。
error: ambiguous overload for ‘operator*’ (operand types are ‘double’ and ‘const cd’)
return pow(eps1/e0*kz2,2)-pow(eps2/e0*kz1*tanh(dist*1e-10*kz1/( x *I)),2);
~~~^~
In file included from libs/calc/include/calculation.h:12:0,
from scripts/dist_dependence.cpp:2:
libs/calc/include/complex_double.h:49:4: note: candidate: cd operator*(const int&, const cd&)
cd operator*(const int& x, const cd& z)
因为手动操作符定义(上面)也可以用于带有 cd
的 double
- 这已经在标准库中定义了。
现在可以通过定义来解决上述问题
cd operator*(const double& x, const cd& z)
{
return cd(x*z.real(),x*z.imag());
}
然而,这会阻止以下情况:
除此之外,我还想要从 cd
到 double
的转换,以便可以将复数(无需显式转换)传递给取实数的函数 (double
类型) 参数。 (如果虚部为零,则将 cd
转换为 double
,否则会抛出错误或其他内容)。
问题是当我定义(除了 double
-cd
operator*
:
operator double() {
if (imag()==0.0) return real();
throw "trying to cast a cd with non-zero imaginary part to double";
}
里面 cd
class.
它吐出以下内容:
warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second:
这里只给出了 operator*
的例子,但我也想对其他数学二元运算做这个。
您的问题在这里:
So I extended the complex<double>
type as cd
这是初学者常犯的错误,他们认为继承是所有问题的答案,而实际上它是许多问题的根源。
只要定义一个没有继承的工作类型,一切都会开箱即用:
using cd = std::complex<double>;
constexpr cd i{0 , 1};
int main (int , char **)
{
cd x{ 1, 3};
std::cout << x << '\n';
std::cout << x*i << '\n';
std::cout << x*i + 3.2 << '\n';
return 0;
}
https://wandbox.org/permlink/OfOfonJFrTInR0ib
免责声明:cd
不是此符号的最佳名称。考虑一些更具描述性的东西
我创建了一个我认为能说明您的问题的最小示例。希望它也向评论者说明了您要完成的任务。
#include <iostream>
#include <complex>
#include <string>
class cd: public std::complex<double> {
public:
cd(double re, double im):std::complex<double>(re,im),name("var1"){}
operator double(){
if (imag()==0.0) return real();
throw "trying to cast a cd with non-zero imaginary part to double";
}
friend std::ostream& operator<<(std::ostream& os, const cd& z){
os << z.name << "=(" << z.real() << "," << z.imag() << ")";
return os;
}
private:
std::string name;
};
cd operator*(const int& i, const cd& z){
return cd(i*z.real(),i*z.imag());
}
cd operator*(const double& x, const cd& z){
return cd(x*z.real(),x*z.imag());
}
void foo(double x){
std::cout << "foo " << x << std::endl;
}
int main(){
int i=2;
cd z(1,2);
std::cout << i*z << std::endl;
double x=30;
std::cout << x*z << std::endl;
cd zz(3,0);
foo(x*zz);
std::cout << z*zz << std::endl;
}
g++
(版本 7.4.0)
给出以下输出
test_complex_double.cc: In function ‘int main()’:
test_complex_double.cc:48:18: warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second:
std::cout << z*zz << std::endl;
^~
In file included from test_complex_double.cc:2:0:
/usr/include/c++/7/complex:386:5: note: candidate 1: std::complex<_Tp> std::operator*(const std::complex<_Tp>&, const std::complex<_Tp>&) [with _Tp = double]
operator*(const complex<_Tp>& __x, const complex<_Tp>& __y)
^~~~~~~~
test_complex_double.cc:22:4: note: candidate 2: cd operator*(const int&, const cd&)
cd operator*(const int& i, const cd& z){
^~~~~~~~
test_complex_double.cc:48:18: warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second:
std::cout << z*zz << std::endl;
^~
In file included from test_complex_double.cc:2:0:
/usr/include/c++/7/complex:386:5: note: candidate 1: std::complex<_Tp> std::operator*(const std::complex<_Tp>&, const std::complex<_Tp>&) [with _Tp = double]
operator*(const complex<_Tp>& __x, const complex<_Tp>& __y)
^~~~~~~~
test_complex_double.cc:26:4: note: candidate 2: cd operator*(const double&, const cd&)
cd operator*(const double& x, const cd& z){
^~~~~~~~
这只是一个警告,这个例子仍然可以编译。
我认为解决方案是您希望 class 成为 std::complex<double>
的 容器 ,而不是继承它。我假设您想继承,这样您就不必围绕 std::complex<double>
实现的所有内容实现包装函数,但我认为容器方法更有意义,并且还解决了这个特定问题。
这是一个显示容器替代方案的工作示例:
#include <iostream>
#include <complex>
#include <string>
class cd {
public:
cd(double re, double im):val(re,im),name("var1"){}
cd(const std::complex<double>& v):val(v),name("var1"){}
operator double(){
if (val.imag()==0.0) return val.real();
throw "trying to cast a cd with non-zero imaginary part to double";
}
friend std::ostream& operator<<(std::ostream& os, const cd& z){
os << z.name << "=(" << z.real() << "," << z.imag() << ")";
return os;
}
double real() const{return val.real();}
double imag() const{return val.imag();}
cd operator*(const cd& other)const{return val*other.val;}
private:
std::complex<double> val;
std::string name;
};
cd operator*(const int& i, const cd& z){
return cd(i*z.real(),i*z.imag());
}
cd operator*(const double& x, const cd& z){
return cd(x*z.real(),x*z.imag());
}
void foo(double x){
std::cout << "foo " << x << std::endl;
}
int main(){
int i=2;
cd z(1,2);
std::cout << i*z << std::endl;
double x=30;
std::cout << x*z << std::endl;
cd zz(3,0);
foo(x*zz);
std::cout << z*zz << std::endl;
}
编译时没有警告,运行程序产生输出:
var1=(2,4)
var1=(30,60)
foo 90
var1=(3,6)
我是一名物理学家,试图尽量减少在用于计算的代码文件(方程式和函数)中键入类型转换和强制转换。计算通常涉及复数。因此,我将 complex<double>
类型扩展为 cd
以实现紧凑并添加了一些帮助方法。
class cd: public complex<double> { ... }
扩展而不是仅仅使用 typedef
的原因是物理符号 (string
) 和物理单位 (string
) 可以与物理变量一起存储。
现在如果在计算中我有像
这样的实例int i = 2;
cd z(1,2);
cout << i*z;
这会出错,因为没有运算符可以将 int
和 cd
相乘。 (说实话,我认为 C++ 会自动将 int
隐式转换为 double
并使用相关的运算符。)在手动定义这样的运算符后
cd operator*(const int& i, const cd& z)
{
return cd(i*z.real(),i*z.imag());
}
c++ 然后警告像
这样的部分类型转换的歧义double x = 30;
x*z;
下面的x
是double,I
是cd
。
error: ambiguous overload for ‘operator*’ (operand types are ‘double’ and ‘const cd’)
return pow(eps1/e0*kz2,2)-pow(eps2/e0*kz1*tanh(dist*1e-10*kz1/( x *I)),2);
~~~^~
In file included from libs/calc/include/calculation.h:12:0,
from scripts/dist_dependence.cpp:2:
libs/calc/include/complex_double.h:49:4: note: candidate: cd operator*(const int&, const cd&)
cd operator*(const int& x, const cd& z)
因为手动操作符定义(上面)也可以用于带有 cd
的 double
- 这已经在标准库中定义了。
现在可以通过定义来解决上述问题
cd operator*(const double& x, const cd& z)
{
return cd(x*z.real(),x*z.imag());
}
然而,这会阻止以下情况:
除此之外,我还想要从 cd
到 double
的转换,以便可以将复数(无需显式转换)传递给取实数的函数 (double
类型) 参数。 (如果虚部为零,则将 cd
转换为 double
,否则会抛出错误或其他内容)。
问题是当我定义(除了 double
-cd
operator*
:
operator double() {
if (imag()==0.0) return real();
throw "trying to cast a cd with non-zero imaginary part to double";
}
里面 cd
class.
它吐出以下内容:
warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second:
这里只给出了 operator*
的例子,但我也想对其他数学二元运算做这个。
您的问题在这里:
So I extended the
complex<double>
type ascd
这是初学者常犯的错误,他们认为继承是所有问题的答案,而实际上它是许多问题的根源。
只要定义一个没有继承的工作类型,一切都会开箱即用:
using cd = std::complex<double>;
constexpr cd i{0 , 1};
int main (int , char **)
{
cd x{ 1, 3};
std::cout << x << '\n';
std::cout << x*i << '\n';
std::cout << x*i + 3.2 << '\n';
return 0;
}
https://wandbox.org/permlink/OfOfonJFrTInR0ib
免责声明:cd
不是此符号的最佳名称。考虑一些更具描述性的东西
我创建了一个我认为能说明您的问题的最小示例。希望它也向评论者说明了您要完成的任务。
#include <iostream>
#include <complex>
#include <string>
class cd: public std::complex<double> {
public:
cd(double re, double im):std::complex<double>(re,im),name("var1"){}
operator double(){
if (imag()==0.0) return real();
throw "trying to cast a cd with non-zero imaginary part to double";
}
friend std::ostream& operator<<(std::ostream& os, const cd& z){
os << z.name << "=(" << z.real() << "," << z.imag() << ")";
return os;
}
private:
std::string name;
};
cd operator*(const int& i, const cd& z){
return cd(i*z.real(),i*z.imag());
}
cd operator*(const double& x, const cd& z){
return cd(x*z.real(),x*z.imag());
}
void foo(double x){
std::cout << "foo " << x << std::endl;
}
int main(){
int i=2;
cd z(1,2);
std::cout << i*z << std::endl;
double x=30;
std::cout << x*z << std::endl;
cd zz(3,0);
foo(x*zz);
std::cout << z*zz << std::endl;
}
g++
(版本 7.4.0)
test_complex_double.cc: In function ‘int main()’:
test_complex_double.cc:48:18: warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second:
std::cout << z*zz << std::endl;
^~
In file included from test_complex_double.cc:2:0:
/usr/include/c++/7/complex:386:5: note: candidate 1: std::complex<_Tp> std::operator*(const std::complex<_Tp>&, const std::complex<_Tp>&) [with _Tp = double]
operator*(const complex<_Tp>& __x, const complex<_Tp>& __y)
^~~~~~~~
test_complex_double.cc:22:4: note: candidate 2: cd operator*(const int&, const cd&)
cd operator*(const int& i, const cd& z){
^~~~~~~~
test_complex_double.cc:48:18: warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second:
std::cout << z*zz << std::endl;
^~
In file included from test_complex_double.cc:2:0:
/usr/include/c++/7/complex:386:5: note: candidate 1: std::complex<_Tp> std::operator*(const std::complex<_Tp>&, const std::complex<_Tp>&) [with _Tp = double]
operator*(const complex<_Tp>& __x, const complex<_Tp>& __y)
^~~~~~~~
test_complex_double.cc:26:4: note: candidate 2: cd operator*(const double&, const cd&)
cd operator*(const double& x, const cd& z){
^~~~~~~~
这只是一个警告,这个例子仍然可以编译。
我认为解决方案是您希望 class 成为 std::complex<double>
的 容器 ,而不是继承它。我假设您想继承,这样您就不必围绕 std::complex<double>
实现的所有内容实现包装函数,但我认为容器方法更有意义,并且还解决了这个特定问题。
这是一个显示容器替代方案的工作示例:
#include <iostream>
#include <complex>
#include <string>
class cd {
public:
cd(double re, double im):val(re,im),name("var1"){}
cd(const std::complex<double>& v):val(v),name("var1"){}
operator double(){
if (val.imag()==0.0) return val.real();
throw "trying to cast a cd with non-zero imaginary part to double";
}
friend std::ostream& operator<<(std::ostream& os, const cd& z){
os << z.name << "=(" << z.real() << "," << z.imag() << ")";
return os;
}
double real() const{return val.real();}
double imag() const{return val.imag();}
cd operator*(const cd& other)const{return val*other.val;}
private:
std::complex<double> val;
std::string name;
};
cd operator*(const int& i, const cd& z){
return cd(i*z.real(),i*z.imag());
}
cd operator*(const double& x, const cd& z){
return cd(x*z.real(),x*z.imag());
}
void foo(double x){
std::cout << "foo " << x << std::endl;
}
int main(){
int i=2;
cd z(1,2);
std::cout << i*z << std::endl;
double x=30;
std::cout << x*z << std::endl;
cd zz(3,0);
foo(x*zz);
std::cout << z*zz << std::endl;
}
编译时没有警告,运行程序产生输出:
var1=(2,4)
var1=(30,60)
foo 90
var1=(3,6)