C++ 具有共享功能的类模板专门化
我正在使用模板向量类型编写一个简单的数学库:C++ 具有共享功能的类模板专门化,c++,templates,template-specialization,C++,Templates,Template Specialization,我正在使用模板向量类型编写一个简单的数学库: template<typename T, size_t N> class Vector { public: Vector<T, N> &operator+=(Vector<T, N> const &other); // ... more operators, functions ... }; 但现在我重复了通用模板中已经存在的所有内容 我也可以使用继承。将通
template<typename T, size_t N>
class Vector {
public:
Vector<T, N> &operator+=(Vector<T, N> const &other);
// ... more operators, functions ...
};
但现在我重复了通用模板中已经存在的所有内容
我也可以使用继承。将通用模板重命名为VectorBase
,我可以这样做:
template<typename T, size_t N>
class Vector : public VectorBase<T, N> {
};
template<typename T>
class Vector<T, 3> : public VectorBase<T, 3> {
public:
T x() const;
T y() const;
};
我可以给Vector
一个隐式转换构造函数来实现这一点:
template<typename T, size_t N>
class Vector : public VectorBase<T, N> {
public:
Vector(VectorBase<T, N> const &other);
};
模板
类向量:公共向量库{
公众:
向量(向量基常数和其他);
};
然而,现在我正在从Vector
转换到VectorBase
,然后再转换回来。尽管这些类型在内存中是相同的,而且编译器可能会将所有这些都优化掉,但它感觉很笨重,而且我真的不希望在本质上是编译时问题的情况下有潜在的运行时开销
有没有其他方法可以解决这个问题?这是我不久前在使用C++0x特性时想到的一个方法。在这里使用的唯一C++0x特性是
静态断言
,因此您可以使用Boost来替换它
基本上,我们可以使用一个静态大小检查函数来检查给定的索引是否小于向量的大小。如果索引超出范围,我们使用静态断言生成编译器错误:
template <std::size_t Index>
void size_check_lt() const
{
static_assert(Index < N, "the index is not within the range of the vector");
}
然后我们可以编写简单的访问器,如下所示:
T& x() { return get<0>(); }
T& y() { return get<1>(); }
T& z() { return get<2>(); }
T&x(){return get();}
T&y(){return get();}
T&z(){return get();}
如果向量只有两个元素,则可以使用x和y,但不能使用z。如果向量有三个或更多元素,则可以使用所有三个元素
最后,我对构造函数做了同样的事情——我为维度2、3和4的向量创建了构造函数,并添加了size\u check\u eq
,允许它们分别为维度2、3和4的向量实例化。如果有人感兴趣的话,我今晚回家后可以试着发布完整的代码
我中途放弃了这个项目,所以这样做可能会有一些我没有遇到的巨大问题。。。至少这是一个可以考虑的选项。
最简单的方法是什么?使用外部功能:
template <class T>
T& x(Vector<T,2>& vector) { return vector.at<0>(); }
template <class T>
T const& x(Vector<T,2> const& vector) { return vector.at<0>(); }
模板
T&x(Vector&Vector){returnvector.at();}
模板
T const&x(Vector const&Vector){return Vector.at();}
在模板编程中,使用外部函数是添加功能的最简单方法,这仅仅是因为您刚刚遇到了专门化问题
另一方面,您仍然可以为任何
N
提供x
、y
和z
,或者使用enable_if
/禁用_if
功能来限制范围。我不知道您是否可以绕过赋值运算符的键入问题,但通过定义各种操作符的模板版本、实现它们的帮助函数,然后使用继承,您可以使工作变得更轻松
template <typename T, std::size_t N>
class fixed_array {
public:
virtual ~fixed_array() {}
template <std::size_t K>
fixed_array& operator+=(fixed_array<T,K> const& other) {
for (std::size_t i=0; i<N; ++i)
this->contents[i] += other[i];
return *this;
}
template <std::size_t K>
fixed_array& operator=(fixed_array<T,K> const& other) {
assign_from(other);
return *this;
}
T& operator[](std::size_t idx) {
if (idx >= N)
throw std::runtime_error("invalid index in fixed_array[]");
return contents[idx];
}
protected:
template <std::size_t K>
void assign_from(fixed_array<T,K> const& other) {
for (std::size_t i=0; i<N; ++i)
this->contents[i] = other[i];
}
private:
T contents[N];
};
template <typename T>
class fixed_2d_array: public fixed_array<T,2> {
public:
T x_coord() const { return (*this)[0]; }
T y_coord() const { return (*this)[1]; }
template <std::size_t K>
fixed_2d_array& operator=(fixed_array<T,K> const& other) {
assign_from(other);
return *this;
}
};
int
main() {
fixed_array<int,5> ary1;
fixed_2d_array<int> ary2;
ary2 = ary1;
ary1 = ary2;
ary2 += ary1;
ary1 += ary2;
return 0;
}
模板
类固定数组{
公众:
虚~fixed_数组(){}
模板
固定数组和运算符+=(固定数组常量和其他){
对于(std::size_t i=0;icontents[i]+=other[i];
归还*这个;
}
模板
固定数组和运算符=(固定数组常量和其他){
从(其他)处分配;
归还*这个;
}
T&T运算符[](标准::大小\u T idx){
如果(idx>=N)
抛出std::runtime_错误(“fixed_数组[]中的索引无效”);
返回内容[idx];
}
受保护的:
模板
无效分配自(固定数组常量和其他){
对于(std::size_t i=0;i内容[i]=其他[i];
}
私人:
T含量[N];
};
模板
类固定数组:公共固定数组{
公众:
T x_coord()常量{return(*this)[0];}
T y_coord()常量{return(*this)[1];}
模板
fixed_2d_数组和运算符=(fixed_数组常量和其他){
从(其他)处分配;
归还*这个;
}
};
int
main(){
固定数组ary1;
固定的二维数组ary2;
ary2=ary1;
ary1=ary2;
ary2+=ary1;
ary1+=ary2;
返回0;
}
我想你可以用它来解决这个问题。这个成语用在
模板
类向量基
{
公众:
/*如有必要,请使用static_cast,因为我们知道'ChildT'是一个'VectorBase'*/
友元ChildT运算符*(双lhs,ChildT常量和rhs){/**/}
友元ChildT运算符*(ChildT常量和lhs,双rhs){/**/}
};
模板
类向量:公共向量库
{
};
模板
类向量:公共向量库
{
公众:
tx()常数{}
T y()常数{}
};
无效测试()
{
向量v;
向量w;
w=5*v;
w=v*5;
v、 x();
向量y;
向量z;
y=5*z;
y=z*5;
//z、 x();//错误!!
}
为什么不让x()
和y()
自由函数采用Vector
?例如模板tx(const Vector&v);
成为可能,但是v.x()
对我来说比x(v)
更有意义。另外,我想添加一些专门的构造函数,例如Vector(T,T)
,构造函数不能是自由函数。不可以,但是你可以用std::make__pair
的样式使用按值返回对象的函数。我迟到了四天,但我想我的答案解决了这个问题:-)我在做了一段时间的其他事情后才重新考虑这个问题,这确实是最好的解决方案。万分感谢!
T& x() { return get<0>(); }
T& y() { return get<1>(); }
T& z() { return get<2>(); }
template <class T>
T& x(Vector<T,2>& vector) { return vector.at<0>(); }
template <class T>
T const& x(Vector<T,2> const& vector) { return vector.at<0>(); }
template <typename T, std::size_t N>
class fixed_array {
public:
virtual ~fixed_array() {}
template <std::size_t K>
fixed_array& operator+=(fixed_array<T,K> const& other) {
for (std::size_t i=0; i<N; ++i)
this->contents[i] += other[i];
return *this;
}
template <std::size_t K>
fixed_array& operator=(fixed_array<T,K> const& other) {
assign_from(other);
return *this;
}
T& operator[](std::size_t idx) {
if (idx >= N)
throw std::runtime_error("invalid index in fixed_array[]");
return contents[idx];
}
protected:
template <std::size_t K>
void assign_from(fixed_array<T,K> const& other) {
for (std::size_t i=0; i<N; ++i)
this->contents[i] = other[i];
}
private:
T contents[N];
};
template <typename T>
class fixed_2d_array: public fixed_array<T,2> {
public:
T x_coord() const { return (*this)[0]; }
T y_coord() const { return (*this)[1]; }
template <std::size_t K>
fixed_2d_array& operator=(fixed_array<T,K> const& other) {
assign_from(other);
return *this;
}
};
int
main() {
fixed_array<int,5> ary1;
fixed_2d_array<int> ary2;
ary2 = ary1;
ary1 = ary2;
ary2 += ary1;
ary1 += ary2;
return 0;
}
template<typename ChildT, typename T, int N>
class VectorBase
{
public:
/* use static_cast if necessary as we know that 'ChildT' is a 'VectorBase' */
friend ChildT operator*(double lhs, ChildT const &rhs) { /* */ }
friend ChildT operator*(ChildT const &lhs, double rhs) { /* */ }
};
template<typename T, size_t N>
class Vector : public VectorBase<Vector<T,N>, T, N>
{
};
template<typename T>
class Vector<T, 3> : public VectorBase<Vector<T, 3>, T, 3>
{
public:
T x() const {}
T y() const {}
};
void test()
{
Vector<float, 3> v;
Vector<float, 3> w;
w = 5 * v;
w = v * 5;
v.x();
Vector<float, 5> y;
Vector<float, 5> z;
y = 5 * z;
y = z * 5;
//z.x(); // Error !!
}