#ifndef COMPLEX_HPP
#define COMPLEX_HPP
#if __cplusplus < 202002L
#error "C++20 or later is required."
#endif
#include <iostream>
#include <concepts>
#include <type_traits>
#include <cmath>
template<typename T>
concept AllowedType = std::same_as<T, int> ||
std::same_as<T, long> ||
std::same_as<T, long long> ||
std::same_as<T, float> ||
std::same_as<T, double>;
template<AllowedType T>
class complex
{
protected:
T m_real;
T m_imag;
public:
complex();
explicit complex(const T, const T);
complex(const complex<T>&);
T real() const;
T imag() const;
void set_real(const T);
void set_imag(const T);
complex<T>& operator=(const complex<T>&);
complex<T> operator+(const complex<T>&) const;
complex<T> operator-(const complex<T>&) const;
complex<T> operator*(const complex<T>&) const;
complex<T> operator/(const complex<T>&) const;
complex<T>& operator+=(const complex<T>&);
complex<T>& operator-=(const complex<T>&);
complex<T>& operator*=(const complex<T>&);
complex<T>& operator/=(const complex<T>&);
template<AllowedType U>
friend std::ostream& operator<<(std::ostream&, const complex<U>&);
template<AllowedType U>
friend std::istream& operator>>(std::istream&, complex<U>&);
};
// -------------------- Implementations --------------------
template<AllowedType T>
complex<T>::complex()
: m_real(0), m_imag(0)
{
}
template<AllowedType T>
complex<T>::complex(const T r, const T i)
: m_real(r), m_imag(i)
{
}
template<AllowedType T>
complex<T>::complex(const complex<T>& other)
: m_real(other.m_real), m_imag(other.m_imag)
{
}
template<AllowedType T>
T complex<T>::real() const
{
return m_real;
}
template<AllowedType T>
T complex<T>::imag() const
{
return m_imag;
}
template<AllowedType T>
void complex<T>::set_real(const T r)
{
m_real = r;
}
template<AllowedType T>
void complex<T>::set_imag(const T i)
{
m_imag = i;
}
template<AllowedType T>
complex<T>& complex<T>::operator=(const complex<T>& other)
{
m_real = other.m_real;
m_imag = other.m_imag;
return *this;
}
template<AllowedType T>
complex<T> complex<T>::operator+(const complex<T>& rhs) const
{
return complex<T>(m_real + rhs.m_real, m_imag + rhs.m_imag);
}
template<AllowedType T>
complex<T> complex<T>::operator-(const complex<T>& rhs) const
{
return complex<T>(m_real - rhs.m_real, m_imag - rhs.m_imag);
}
template<AllowedType T>
complex<T> complex<T>::operator*(const complex<T>& rhs) const
{
T r = m_real * rhs.m_real - m_imag * rhs.m_imag;
T i = m_real * rhs.m_imag + m_imag * rhs.m_real;
return complex<T>(r, i);
}
template<AllowedType T>
complex<T> complex<T>::operator/(const complex<T>& rhs) const
{
T denom = rhs.m_real * rhs.m_real + rhs.m_imag * rhs.m_imag;
T r = (m_real * rhs.m_real + m_imag * rhs.m_imag) / denom;
T i = (m_imag * rhs.m_real - m_real * rhs.m_imag) / denom;
return complex<T>(r, i);
}
template<AllowedType T>
complex<T>& complex<T>::operator+=(const complex<T>& rhs)
{
m_real += rhs.m_real;
m_imag += rhs.m_imag;
return *this;
}
template<AllowedType T>
complex<T>& complex<T>::operator-=(const complex<T>& rhs)
{
m_real -= rhs.m_real;
m_imag -= rhs.m_imag;
return *this;
}
template<AllowedType T>
complex<T>& complex<T>::operator*=(const complex<T>& rhs)
{
T r = m_real * rhs.m_real - m_imag * rhs.m_imag;
T i = m_real * rhs.m_imag + m_imag * rhs.m_real;
m_real = r;
m_imag = i;
return *this;
}
template<AllowedType T>
complex<T>& complex<T>::operator/=(const complex<T>& rhs)
{
T denom = rhs.m_real * rhs.m_real + rhs.m_imag * rhs.m_imag;
T r = (m_real * rhs.m_real + m_imag * rhs.m_imag) / denom;
T i = (m_imag * rhs.m_real - m_real * rhs.m_imag) / denom;
m_real = r;
m_imag = i;
return *this;
}
template<AllowedType T>
std::ostream& operator<<(std::ostream& out, const complex<T>& c)
{
out << '(' << c.m_real;
if (c.m_imag >= 0) {
out << '+';
}
out << c.m_imag << 'i' << ')';
return out;
}
template<AllowedType T>
std::istream& operator>>(std::istream& in, complex<T>& c)
{
char ch;
T r, i;
in >> ch;
if (ch != '(') {
in.setstate(std::ios::failbit);
return in;
}
in >> r >> i >> ch;
if (ch != 'i') {
in.setstate(std::ios::failbit);
return in;
}
in >> ch;
if (ch != ')') {
in.setstate(std::ios::failbit);
return in;
}
c.m_real = r;
c.m_imag = i;
return in;
}
#endif // COMPLEX_HPP