C++模板<Operator>

Fil*_*ues 2 c++ templates operator-overloading

我正在构建一个BigInt类,当重载运算符时,| 和^,都将具有相似的函数语法,我想知道是否可以模拟运算符本身:

template<operator K> 
BigInt operator K( const BigInt& a, const BigInt& b )
{
 BigInt Result = 0;
 uint64_t Max = max(a.GetSize() , b.GetSize()) /* max(a,b) is defined outside */
 for (uint64_t n=0; n < Max; n++)
 {
  Result[n] = a[n] K b[N];
 }
 return Result;
}
Run Code Online (Sandbox Code Playgroud)

其中A [n]返回带有第n个数字(二进制​​)的bool,并将其应用于运算符&,| 和^,这样我就不会写出3个运算符重载,它们对于2个字母的例外都是相同的.

我知道这种语法不起作用,但我问是否有任何方法可以做你可能期望这种语法做的事情:用&替换K,| 或^,只有你在代码中写(a和b)时的那些.

如果它有帮助,这是我对类的定义:

class BigInt
{
private:
    vector<bool> num;

public:
    /* Constructors */
    BigInt();
    template<class T> BigInt(T);

    /* Class Methods */
    void RLZ(); /* Remove Leading Zeroes */
    uint64_t GetSize() const;
    void print();

    /* Operator Overloads */
    std::vector<bool>::reference operator[] (uint64_t);
    bool operator[] (uint64_t) const;
    BigInt& operator=(const BigInt&);
};
Run Code Online (Sandbox Code Playgroud)

0x5*_*453 7

一个想法是定义一个在操作符函数上模板化的辅助函数(因为你不能在操作符本身上模板化),然后在相应的BigInt操作符的定义中实例化你的模板.例如:

template <class OperatorFn> 
BigInt bitwiseOperator(const BigInt& a, const BigInt& b) const
{
    BigInt Result = 0;
    uint64_t Max = max(a.GetSize(), b.GetSize());
    for (uint64_t n=0; n < Max; n++)
    {
        Result[n] = OperatorFn{}(a[n], b[N]);
    }
    return Result;
}
BigInt operator&(const BigInt& a, const BigInt& b) const { return bitwiseOperator<std::bit_and<bool>>(a, b); }
BigInt operator|(const BigInt& a, const BigInt& b) const { return bitwiseOperator<std::bit_or<bool>>(a, b); }
BigInt operator^(const BigInt& a, const BigInt& b) const { return bitwiseOperator<std::bit_xor<bool>>(a, b); }
Run Code Online (Sandbox Code Playgroud)

  • @FilipeRodrigues确保你#include <functional>`,你可能需要将`OperatorFn(a [n],b [N]);`更改为`OperatorFn {}(a [n],b [N]) ;`因为`bit_and`,其余的实际上是函数对象,而不是函数. (2认同)

Yak*_*ont 5

我会写这个:

template<class F>
BigInt& bitwiseReplace( F&& f, BigInt& lhs, BigInt const& rhs ) {
  auto max = (std::max)(lhs.GetSize(), rhs.GetSize());
  for (uint64_t i=0; i < max; ++i)
    lhs[i] = f( lhs[i], rhs[i] );
  return lhs;
}
Run Code Online (Sandbox Code Playgroud)

请注意,我lhs通过引用并修改它.这是故意的.这对应于&=|=.

template<class F>
BigInt bitwiseCreate( F&& f, BigInt lhs, BigInt const& rhs ) {
  bitwiseReplace( std::forward<F>(f), lhs, rhs );
  return lhs;
}
Run Code Online (Sandbox Code Playgroud)

这对应于+|.

在你的班上:

BigInt& operator=(const BigInt&)=default;
BigInt& operator=(BigInt&&)=default;
BigInt(const BigInt&)=default;
BigInt(BigInt&&)=default;
Run Code Online (Sandbox Code Playgroud)

有默认的移动/复制分配/构造,因为它们在这里做正确的事情.

现在你只需写一行:

BigInt& operator&=( BigInt const& rhs ) { return bitwiseReplace( std::bit_and<bool>{}, *this, rhs ); }
BigInt& operator|=( BigInt const& rhs ) { return bitwiseReplace( std::bit_or<bool>{}, *this, rhs ); }

friend BigInt operator&( BigInt lhs, BigInt const& rhs ) { return bitwiseCreate( std::bit_and<bool>{}, std::move(lhs), rhs ); }
friend BigInt operator|( BigInt lhs, BigInt const& rhs ) { return bitwiseCreate( std::bit_or<bool>{}, std::move(lhs), rhs ); }
Run Code Online (Sandbox Code Playgroud)

这需要少量的胶水代码.

左侧由值表示意味着

auto r = a | b | c;
Run Code Online (Sandbox Code Playgroud)

是有效的 - 结果a | b被移动(实际上被省略)(a|b) | c没有执行复制.

这样做的另一个好处是你可以std::vector<bool>用一个替换你std::vector<uint32_t>.只需编写wordwiseReplacewordwiseCreate采用一个函数,并uint32_t以非常类似的方式对每个函数进行操作.

你可以用多一点额外的工作,甚至实现+-这种方式.功能对象可以携带进位信息.您必须检查末端是否有溢出/下溢并进行调整.

*/需要更多的工作.

  • @FilipeRodrigues我的意思是,你的big int应该用32位块而不是1位块构造.所以128位值而不是`num.size()== 128`有'num.size()== 4`.这允许*更快*``和`-`等,因为你可以使用机器`+`和`-`而不必手动携带每一位. (2认同)