在C++中如何获得**幂运算符

· · 科技·工程

前言

学 Python 时,我们认识了一个运算符 **,其可以计算次幂。

我们想要将其迁移过来。

构建

不妨定义一个数类,我们希望其可以有正常的四则运算和指幂运算符操作,且有 C++ 风格输入输出。

也就是说,我们希望下面这一段程序正确运行

int main()
{
    Num A,B;
    std::cin>>A>>B;
    std::cout<<A+B<<' '<<A-B<<' '<<A*B<<' '<<A/B<<' '<<A**B<<std::endl;
    return 0;
}

写出接口

class Num
{
    ll num;
public:
    Num(ll n=0ll):num(n){}
    TT operator*(){return num;}
    friend Num operator*(Num,Num);
    friend Num operator-(Num,Num);
    friend Num operator+(Num,Num);
    friend Num operator/(Num,Num);
    friend Num operator-(Num);
    friend Num operator**(Num,Num);//?
    friend Num ksm(Num,Num);
    friend std::ostream& operator<<(std::ostream&,Num);
    friend std::istream& operator>>(std::istream&,Num&);
};

CE 了!

C++ 重载运算符必须是已有的运算符,而 C++ 自身没有该运算符。

就要这么放弃了么……

停!我们可以这么做

#include <iostream>
typedef long long ll;
class Num;
class TT
{
    ll num;
public:
    explicit TT(ll n=0ll):num(n){}
    friend Num operator*(Num,TT);
};
class Num
{
    ll num;
public:
    Num(ll n=0ll):num(n){}
    TT operator*(){return (TT)num;}
    friend Num operator*(Num,Num);
    friend Num operator-(Num,Num);
    friend Num operator+(Num,Num);
    friend Num operator/(Num,Num);
    friend Num operator-(Num);
    friend Num operator*(Num,TT);
    friend Num ksm(Num,Num);
    friend std::ostream& operator<<(std::ostream&,Num);
    friend std::istream& operator>>(std::istream&,Num&);
};

我们让 C++ 将 A**B 识别成 A*(*B),这样两个运算符都是已有的。

运行一下?

#include <iostream>
typedef long long ll;
class Num;
class TT
{
    ll num;
public:
    explicit TT(ll n=0ll):num(n){}
    friend Num operator*(Num,TT);
};
class Num
{
    ll num;
public:
    Num(ll n=0ll):num(n){}
    TT operator*(){return (TT)num;}
    friend Num operator*(Num,Num);
    friend Num operator-(Num,Num);
    friend Num operator+(Num,Num);
    friend Num operator/(Num,Num);
    friend Num operator-(Num);
    friend Num operator*(Num,TT);
    friend Num ksm(Num,Num);
    friend std::ostream& operator<<(std::ostream&,Num);
    friend std::istream& operator>>(std::istream&,Num&);
};
Num operator*(Num A,Num B)
{
    return A.num*B.num;
}
Num operator+(Num A,Num B)
{
    return A.num+B.num;
}
Num operator-(Num A,Num B)
{
    return A.num-B.num;
}
Num ksm(Num A,Num B)
{
    ll r=1ll;
    ll a=A.num,b=B.num;
    while(b)
    {
        if(b&1)r=r*a;
        a=a*a;
        b>>=1;
    }
    return r;
}
Num operator-(Num A)
{
    return -A.num;
}
Num operator/(Num A,Num B)
{
    return A.num/B.num;
}
Num operator*(Num A,TT B)
{
    return ksm(A,B.num);
}
std::ostream& operator<<(std::ostream& out,Num x)
{
    out<<x.num;
    return out;
}
std::istream& operator>>(std::istream& in,Num& x)
{
    in>>x.num;
    return in;
}

int main()
{
    Num A,B;
    std::cin>>A>>B;
    std::cout<<A+B<<' '<<A-B<<' '<<A*B<<' '<<A/B<<' '<<A**B<<std::endl;
    return 0;
}

输入 4 2,输出 6 2 8 2 16。

正确!

左结合?右结合?

cout<<(Num)2**(Num)2**(Num)3 的输出是什么呢?

按照 python,应该是 2^8=256,但是实际输出 4^3=64。

我们需要维护一个右结合。

可以额外维护一个类 UU,记录整个序列,然后隐式转换时从右向左计算。

#include <iostream>
#include <vector>
typedef long long ll;
class Num;
class TT;
Num ksm(Num,Num);
class UU
{
    std::vector<Num> sz;
public:
    UU():sz(std::vector<Num>()){}
    operator Num();
    UU& operator*(TT);
    friend UU operator*(Num,TT);
};
class TT
{
    ll num;
public:
    explicit TT(ll n=0ll):num(n){}
    friend UU operator*(Num,TT);
    friend UU& UU::operator*(TT);
};
class Num
{
    ll num;
public:
    Num(ll n=0ll):num(n){}
    TT operator*()const{return (TT)num;}
    friend Num operator*(Num,Num);
    friend Num operator-(Num,Num);
    friend Num operator+(Num,Num);
    friend Num operator/(Num,Num);
    friend Num operator-(Num);
    friend UU operator*(Num,TT);
    friend Num ksm(Num,Num);
    friend std::ostream& operator<<(std::ostream&,Num);
    friend std::istream& operator>>(std::istream&,Num&);
};
UU::operator Num()
{
    if(!sz.size())return 1ll;
    while(sz.size()>1)
    {
        Num b=*sz.rbegin();
        sz.pop_back();
        Num a=*sz.rbegin();
        sz.pop_back();
        sz.push_back(ksm(a,b));
    }
    return *sz.begin();
}
UU& UU::operator*(TT x)
{
    sz.push_back(x.num);
    return *this;
}
Num operator*(Num A,Num B)
{
    return A.num*B.num;
}
Num operator+(Num A,Num B)
{
    return (A.num+B.num);
}
Num operator-(Num A,Num B)
{
    return A.num-B.num;
}
Num ksm(Num A,Num B)
{
    ll r=1ll;
    ll a=A.num,b=B.num;
    while(b)
    {
        if(b&1)r=r*a;
        a=a*a;
        b>>=1;
    }
    return r;
}
Num operator-(Num A)
{
    return -A.num;
}
Num operator/(Num A,Num B)
{
    return A.num/B.num;
}
UU operator*(Num A,TT B)
{
    UU R;
    R.sz.push_back(A);
    R.sz.push_back(B.num);
    return R;
}
std::ostream& operator<<(std::ostream& out,Num x)
{
    out<<x.num;
    return out;
}
std::istream& operator>>(std::istream& in,Num& x)
{
    in>>x.num;
    return in;
}

int main()
{
    Num A,B,C;
    std::cin>>A>>B>>C;
    std::cout<<A**B**C<<std::endl;
    return 0;
}

现在,输出为正确的 256。