我正在实现一个Big Integer库,用户可以在固定精度或任意精度整数之间进行选择。由于很大一部分代码是在两个实体之间共享的,所以我决定使用CRTP只执行一次Integer操作。
简而言之,有一个名为UInteger的基类和两个名为UIntegerFP(固定精度)和UIntegerAP(任意精度)的派生类。
遵循实施的框架:
template <typename Derived>
class UInteger
{
public:
UInteger<Derived> &operator +=(const UInteger<Derived> &rhs);
...
};
template <int blocks>
class UIntegerFP : public UInteger<UIntegerFP>
{
public:
int get_size() { return m_len; }
void set_size(int size) { m_len = len; }
private:
std::array<uint32_t, blocks> m_data;
int m_len;
};
class UIntegerAP : public UInteger<UIntegerAP>
{
public:
int get_size() { return m_data.size(); }
void set_size(int size) { m_data.resize(len); }
private:
std::vector<uint32_t> m_data;
};
基类使用派生类公开的几个方法与依赖于实现的方面进行交互(例如get_size / set_size)。
我的问题:
我想实现一个全局二元运算符+(),它以这种方式在UInteger“generic”头文件中按值返回操作的结果:
template <typename Derived>
UInteger<Derived> operator+(const UInteger<Derived> &x0,
const UInteger<Derived> &x1)
{
Derived res = static_cast<Derived>(x0);
x0 += x1;
return x0;
}
问题在于,由于结果是按值返回的,因此会将其转换为基类类型,从而忽略实现细节(例如,调用m_data向量析构函数)。 显然,如果我定义函数以按值返回Derived类型,我就不会遇到这个问题:
template <typename Derived>
Derived operator+(const UInteger<Derived> &x0,
const UInteger<Derived> &x1)
{
Derived res = static_cast<Derived>(x0);
x0 += x1;
return x0;
}
但我不太喜欢这种方法,特别是从设计的角度来看。
这种问题有更好的解决方案吗?也许我应该直接为派生类定义这样的运算符? 是否有人认为CRTP在这里不太合适,也许以这种方式直接实现一个UInteger类更好:
template <bool dynamic = true>
class UInteger
{
...
private:
std::array<uint32_t> m_data;
int m_len; <- how much of m_data array is actually in use
}
如果bool“dynamic”值为false,我永远不会重新分配向量,获取类似于UIntegerFP模板类的东西。也许(如果编译器足够智能),因为布尔值是一个const模板参数,我还可以获得类似条件代码编译的东西吗?!
非常欢迎任何类型的建议,
谢谢, 的Davide
答案 0 :(得分:0)
我不太明白为什么要以这种方式使用CRTP。
当仅通过派生方法完成内存管理时,CRTP是实现/Users/balterma/Library/Enthought/Canopy_64bit/User/lib/python2.7/sitepackages/matplotlib/colors.py:584: RuntimeWarning: invalid value encountered in less cbook._putmask(xa, xa < 0.0, -1)
和=
操作的实际细节的自然方式。这种设计清楚地将算术和内存管理这两项任务分为不同的类。然后,+=
(二进制)运算符最好作为独立的函数模板实现。
这样的事情:
+
答案 1 :(得分:0)
在operator+
实现中,实际上,您将函数返回类型设置为:
UIntegerAP
如果其中一个模板类型为UIntegerAP
。Ulhs
,否则(此处我认为您打算UIntegerFP
)。是吗?
现在......如果UIntegerAP
也是模板怎么办?例如,定义如下:
template <typename block_type>
class UIntegerAP
{
....
private:
std::vector<block_type> m_data;
}
我不能再在UIntegerAP
声明中使用operator+
类型了。