我有一个可以实现不同基类型的类tPoint,所以
template<typename T>class tPoint{
T x;
T y;
public:
void Set(T ix, T iy){x=ix;y=iy;}
};
当类型T是int tPoint<int>
时,我想要一个特殊的Set(float,float),所以我可以在赋值之前对值进行舍入。
我认为我可以专业化:
template<> void tPoint<int>::Set(float ix,float iy){x=ix+.5; y=iy+.5;}
这样编译器就会抱怨类定义中没有匹配的函数。
但是如果我在类Set(float,float)中声明它然后它已经定义了(当它为T = float编译时)
我希望自己清楚明白,对此采取什么干净措施或者我做错了什么?谢谢!
答案 0 :(得分:5)
你需要专门化这个课程,如下所示:
template<> class tPoint<int>{
int x;
int y;
public:
void Set(int ix, int iy){x=ix;y=iy;}
void Set(float ix, float iy){x = ix+0.5; y = iy+0.5;}
};
答案 1 :(得分:3)
您遇到的问题与T
代表int
或float
有关。
如果您查看模板类定义,您会注意到T
部分中typename
之后显示的template
也会显示为Set
的参数方法。
这意味着当您谈到Point<int>
时,只定义了一个 Set
方法,这需要两个int
。每个不同的Point<T>
都有自己的Set(T,T)
方法。
如果您希望使用其他Set
方法,则需要在模板类中声明模板Set
,这样做:
template <typename T>
class Point
{
public:
template <typename Num>
void Set(Num x, Num y);
};
请注意我必须选择不同的模板参数名称。
为了解决您的问题,您可以为float
引入另一种方法,但是您必须为double
和long double
添加另一种方法......很快将变得困难。
最简单的解决方案就是走向暴力:
template <typename Integral>
template <typename Num>
void Point<Integral>::Set(Num x, Num y)
{
this->x = long double(x) + 0.5;
this->y = long double(y) + 0.5;
}
对于int
和al,它几乎没用但是有效。对于浮点,我们使用更大的浮点类型来避免精度损失,然后执行舍入。
显然,如果我们突然想要一个Point<float>
,它就不会起作用,因此我们需要一个基于类型特征的更智能的解决方案。类std::numeric_limits<T>
有一个is_integer
,可以预测我们是否处理整数类型。
template <typename T>
template <typename Num>
void Point<T>::Set(Num x, Num y)
{
if (std::numeric_limits<T>::is_integer &&
!std::numeric_limits<Num>::is_integer)
{
this->x = x + 0.5;
this->y = y + 0.5;
}
else
{
this->x = x;
this->y = y;
}
}
}
我知道将if
用于可以在编译时确定的东西似乎很愚蠢...但不要担心,编译器足够智能做数字它在编译时出来并完全取消if
和未使用的分支;)
答案 2 :(得分:0)
使用boost enable_if来防止浮动版本与float一起实现。
答案 3 :(得分:0)
你最好的选择是:
template<typename T>class tPoint{
T x;
T y;
public:
void Set(T ix, T iy) { set_impl(boost::type<T>(), x, y); }
private:
void set_impl(boost::type<int>, float ...);
template<typename U>
void set_impl(boost::type<U>, T ...);
};
答案 4 :(得分:0)
尽量不要在类中提供Set()的默认实现。这样,浮动就更容易了。