【问题标题】:C++ Template<Operator>C++ 模板<运算符>
【发布时间】:2018-02-16 18:12:47
【问题描述】:

我目前正在构建一个 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;
}

其中 A[n] 返回一个带有 A 的第 n 位(二进制)的布尔值,并将其应用于运算符 &、|和 ^,这样我就不会写 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&);
};

【问题讨论】:

  • 我认为您不能将运算符用作模板参数。我会等待有人证明我错了。

标签: c++ templates operator-overloading


【解决方案1】:

一个想法是定义一个在运算符 function 上模板化的辅助函数(因为您不能在运算符本身上模板化),然后在适当的 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); }

【讨论】:

  • 当我尝试运行它时,g++ 给了我错误“没有匹配的函数来调用 'std::bit_and::bit_and(bool, bool) '”,尽管代码确实使对我来说,这似乎是这个错误之外的完美解决方案。我还不得不删除 const 修饰符,因为它告诉我“非成员函数 'BigInt bitwiseOperator(const BigInt&, const BigInt&) 不能有 cv-qualifier '”但是没有 const 它可以正常工作(函数 const,而不是参数 const )。
  • @FilipeRodrigues 确保你是#include &lt;functional&gt;,你可能需要将OperatorFn(a[n], b[N]); 更改为OperatorFn{}(a[n], b[N]);,因为bit_and 其余的实际上是函数对象,而不是函数。
  • #include 不是必需的,似乎唯一的问题是缺少 {},它现在可以正常工作,我假设 std::bit_and 包含在向量中或 iostream,这是我目前拥有的唯一包含,或者它们不需要包含。
【解决方案2】:

我会这样写:

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;
}

请注意,我引用lhs 并对其进行修改。这是故意的。这对应于&amp;=|=

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

这对应于+|

在你的课堂上:

BigInt& operator=(const BigInt&)=default;
BigInt& operator=(BigInt&&)=default;
BigInt(const BigInt&)=default;
BigInt(BigInt&&)=default;

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

现在你只需要写一行:

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 ); }

这需要少量的胶水代码。

左侧取值表示

auto r = a | b | c;

是高效的——a | b 的结果被移动(实际上被省略了)到(a|b) | c 中,没有执行任何副本。

这样做的另一个好处是您可以用std::vector&lt;uint32_t&gt; 替换您的std::vector&lt;bool&gt;。只需编写wordwiseReplacewordwiseCreate,它们接受一个函数并以非常相似的方式对每个uint32_t 进行操作。

您甚至可以通过一些额外的工作来实现+-。函数对象可以携带进位信息。您必须检查最后是否有溢出/下溢并进行调整。

*/ 需要更多的工作。

【讨论】:

  • 谢谢你的回答,但我觉得这个比另一个稍微复杂和不必要,因为这只是一个供个人使用的小库,如果我做一个更大的库我会考虑这些做法,我有一个 std::vector 的原因是它就像一个 std::bitset,这意味着它比 uint32_t 占用更少的内存,uint32_t 是 32 位 vs 1 位。
  • @FilipeRodrigues 我的意思是,你的大整数应该由 32 位块而不是 1 位块构成。所以一个 128 位的值而不是 num.size()==128num.size()==4。这使得+-快得多,因为您可以使用机器+- 而不必手动携带每个位。
  • 啊,是的,这确实有道理,我过去做过一个类似于你用 uint64_t 说的,但是通过将 uint64_t 类型拼凑在一个动态数组中,而不是一个向量,但是有了这个库,我想尝试创建一个位库,主要是为了获得更多关于位旋转和二进制操作的经验。
猜你喜欢
  • 2012-07-16
  • 2012-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多