返回对 C++11 中复数的实数或 IMAG 值的引用的函数
a function returning reference to real or imag values of a complex number in C++11
>我正在寻找一个函数,该函数返回对 C++11 中复数的实数或 imag 值的引用。在 C++03 我可以说:
complex<double> C; cin >> C.real();
但是在 C++11 中,这给了我一个编译错误,因为 C.real() 返回的值而不是引用。
我发现我可以写这个:
double t; cin >> t; C.real(t);
但这并不简单,例如,如果我想将 c 的实部乘以 2 并将其乘以 1,我应该说:
C.real(2*C.real() + 1);
那是不干净的。
还有其他[干净]的方法可以做到这一点吗?
如果你真的想分离复合体的实部和虚部的输入,你可以尝试IO操纵器的方法。
#include <complex>
#include <iosfwd>
class proxy_complex {
explicit proxy_complex(std::istream& strm, bool f)
: strm_(&strm), flag(f) { }
proxy_complex(const proxy_complex&) = default;
std::istream* strm_;
bool flag; // flag to check whether we're writing real or imag
public:
template<typename T>
std::istream& operator>>(std::complex<T>& c)
{
T n;
if (*strm_ >> n)
flag ? c.real(n) : c.imag(n);
return *strm_;
}
friend proxy_complex operator>>(std::istream& is, proxy_complex(*func)(std::istream&))
{
return func(is);
}
friend proxy_complex real(std::istream&);
friend proxy_complex imag(std::istream&);
};
inline proxy_complex real(std::istream& is)
{
return proxy_complex(is, true);
}
inline proxy_complex imag(std::istream& is)
{
return proxy_complex(is, false);
}
您可以将上述代码放在自己的头文件中(如果这样做,最好将其包装在命名空间中)。
用法:
#include <iostream>
#include "my_header.h"
int main()
{
std::complex<double> c;
std::cin >> real >> c >> imag >> c;
if (std::cin) std::cout << c;
}
希望我猜对你对"干净"的定义是正确的:)
很抱歉是消极的,但你的问题从一个错误的前提开始。关于std::complex
2011标准是否向后兼容。表单代码
complex<double> C; cin >> C.real();
C++从来都不是有效的。2003年标准只给出了杆件函数
T std::complext<T>::real() const;
但不是
const T& std::complext<T>::real() const; // non-standard
T& std::complext<T>::real(); // non-standard
即使某些实现(例如GCC 4.3附带的实现)可能已经实现了这两个。
现在,回答你的问题。显然,最干净的方法是遵循标准的意图。2011 标准增加了以下二传手
void std::complex<T>::real(T);
void std::complex<T>::imag(T);
因此,您现在可以简单地使用这些来分别设置实部或虚部。
但是,这些不能用于获取T&
的函数中,例如operator>>
。为此,您必须做一些令人讨厌的技巧,例如
template<typename T>
inline T& get_real(std::complex<T>&z) { return reinterpret_cast<T(&)[2]>(z)[0]; }
template<typename T>
inline T& get_imag(std::complex<T>&z) { return reinterpret_cast<T(&)[2]>(z)[1]; }
std::complex<double> z;
cin >> get_real(z) >> get_imag(z);
实际上,正如 bames53 的评论中所指出的那样,标准保证std::complex
布局,以便始终有效。
C++11 现在允许
double& re(std::complex<double>& c)
{
return reinterpret_cast<double (&)[2]>(c)[0];
}
double& im(std::complex<double>& c)
{
return reinterpret_cast<double (&)[2]>(c)[1];
}
const double& re(const std::complex<double>& c)
{
return reinterpret_cast<const double (&)[2]>(c)[0];
}
const double& im(const std::complex<double>& c)
{
return reinterpret_cast<const double (&)[2]>(c)[1];
}
用法:
std::complex<double> a;
std::cin >> re(a);
相关引用 §26.4:
此外,如果 a 是类型
cv std::complex<T>*
的表达式,并且表达式a[i]
是针对整数表达式i
明确定义的,则: —reinterpret_cast<cv T*>(a)[2*i]
应指定a[i]
的实数部分,并且 —reinterpret_cast<cv T*>(a)[2*i+1]
应指定a[i]
的虚部。
如果你想操纵真实的部分,你可以直接使用双精度或浮点数。如果你想操纵虚部,你可以有一个唯一的复数std::complex<double> I(0,1)
并将其乘以你想要的值。
例如,您可以不写:C.real(2*C.real() + 1);
,而是可以写:C += C.real() + 1;
然后,您可以在数学表达式中混合双精度与复合体,编译器将使用正确的转换。请参阅示例:
#include <iostream>
#include <complex>
int main(int argc, char* argv[])
{
// Let the user enter a Real number
double c;
std::cin >> c;
// Explicitly convert to a complex
std::complex<double> C = 2*c + 1;
std::cout << C << std::endl;
// Creates a pure imaginary complex number I
std::complex<double> I(0,1);
// Mix together complex and real numbers in the
// same expression
C = C + c*I;
std::cout << C << std::endl;
// Setup a specific value and compare how to achieve
// C.real = 2*C.real + 1
C = 1. + 2.*I;
C.real(2*C.real()+1);
std::complex<double> D = 1. + 2.*I;
D += D.real() + 1;
std::cout << "C=" << C << "tD=" << D << std::endl;
return 0;
}
输出:
$ ./main.exe
1
(3,0)
(3,1)
C=(3,2) D=(3,2)
$ ./main.exe
2
(5,0)
(5,2)
C=(3,2) D=(3,2)
如果您担心这种方法的效率损失,而不是直接通过引用产生影响,您可以查看生成的汇编代码。在我的计算机上,g++
和-O3
一切都是内联的。
不是我知道的。
如果这对您很重要,您可以构造一个帮助程序:
class ModifyReal
{
double d;
complex<double> & c;
public:
ModifyReal(complex<double> & c_) : c(c_), d(numeric_limits<double>::quiet_NaN())
{}
operator double &() { return d; }
~ModifyReal() { c.real(d); }
};
cin >> ModifyReal(C);
但是,除非您有非常令人信服的理由,否则我不完全建议您使用它。("我不喜欢它"不够令人信服。
我确实认为在您的代码中有许多不同的类会妨碍可读性,但是如果您在一些专用实例中使用它,您应该没问题。错误处理可能会变得非常困难(例如,由于 cin 不会抛出无效输入,C 被分配为 nan,而不是未修改。
"干净"是什么意思?不,不要告诉我 - 想想看。
受史蒂夫·杰索普的启发,它只是C += (C + C.conj())/2 + 1;
。
请记住,在复杂的数学中,你不能真正将实部和虚部视为完全独立的分量。这比将它们的相位和大小视为完全独立的组件一样理智。复数的加法在实部和虚部独立完成,但乘法在相位和幅度部分独立完成。
您的示例不是复杂的乘法,因此std::complex
不支持这种乘法是有道理的。
- 将对象数组的引用传递给函数
- 什么时候在C++中返回常量引用是个好主意
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- 何时在引用或唯一指针上使用移动语义
- 如何在c++中使用引用实现类似python的行为
- 编译C++时未定义的引用
- Ctypes wstring通过引用传递
- c++r值引用应用于函数指针
- 理解c++中的引用
- C++取消引用指针.为什么会发生变化
- 如何修复此错误:未定义对"距离(浮点数,浮点数,浮点数,浮点数,浮点数)"的引用
- 我的项目不会像"undefined reference to `grpc::g_core_codegen_interface'"那样使用未定义的引用错误进行编译
- C++Boost Asio Pool线程,带有lambda函数和传递引用变量
- 强制转换为引用类型
- 引用一个已擦除类型(void*)的指针
- 向量元素的引用地址与它所指向的向量元素的地址不同.为什么
- 具有默认值的引用获取函数
- 如何使用基类指针引用派生类成员
- 使用取消引用的指针的多态性会产生意外的结果.为什么?
- 返回对 C++11 中复数的实数或 IMAG 值的引用的函数