用于特定模板专门化的重载成员函数

发布于 2024-10-19 18:21:10 字数 533 浏览 4 评论 0原文

我有一个类 tPoint ,它将实现为具有不同的基类型,因此

template<typename T>class tPoint{
   T x;
   T y;
public:
   void Set(T ix, T iy){x=ix;y=iy;}
};

当类型 T 为 int 时,tPoint,我想要一个特殊的 Set(float, float),以便我可以在之前对值进行四舍五入分配。

我认为通过专业化我可以:

template<> void tPoint<int>::Set(float ix,float iy){x=ix+.5; y=iy+.5;}

这样编译器会抱怨类定义中没有匹配的函数。

但是如果我在类 Set(float,float) 中声明,那么它会说已经定义了(当它编译为 T =float 时)

我希望我自己说清楚,什么是一个干净的方法,否则我做错了什么?谢谢!

I have a class tPoint that would be implemented having different base types so

template<typename T>class tPoint{
   T x;
   T y;
public:
   void Set(T ix, T iy){x=ix;y=iy;}
};

When the type T is int, tPoint<int>, I want a special Set(float, float) so I can round the values before assignation.

I thought that with specialisation I could:

template<> void tPoint<int>::Set(float ix,float iy){x=ix+.5; y=iy+.5;}

This way the compiler complains that there's no matching function in the class definition.

But if I declare in the class Set(float,float) then it says that's already defined (when it compiles for T =float)

I hope I made myself clear, what would be a clean approach to this or I'm doing something wrong? thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

開玄 2024-10-26 18:21:10

您需要专门化该类,如下所示:

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

You need to specialize the class, like this:

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;}
};
怂人 2024-10-26 18:21:10

您面临的问题与 T 代表 intfloat 有关。

如果您查看模板类定义,您会注意到 template 部分中 typename 后面出现的相同 T 也显示为参数到 Set 方法。

这意味着当您谈到 Point 时,只定义了一个 Set 方法,该方法需要两个 int.每个不同的Point都会有自己的Set(T,T)方法。

如果您希望使用不同的 Set 方法,那么您需要在模板类中声明一个模板 Set ,这样做是这样的:

template <typename T>
class Point
{
public:
  template <typename Num>
  void Set(Num x, Num y);
};

注意我如何必须选择不同的模板参数名称。


为了解决您的问题,您可以为 float 引入另一种方法,但是您必须为 doublelong double 引入另一种方法code>...很快就会变得困难。

最简单的解决方案是暴力破解:

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,它就不太有效,因此我们需要一个基于类型特征的更智能的解决方案。 std::numeric_limits 类有一个 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 和未使用的分支;)

The issue you're facing has to do with T standing either for int or float.

If you look at the template class definition, you'll remark that the same T that appears after typename in the template part also appears as parameter to the Set method.

This means that when you speak of Point<int> then there is only one Set method defined, which takes two int. And each different Point<T> will have its own Set(T,T) method.

If you wish for a different Set method, then you need to declare a template Set within the template class, this is done like so:

template <typename T>
class Point
{
public:
  template <typename Num>
  void Set(Num x, Num y);
};

Note how I had to chose a different template parameter name.


In order to solve your problem, you could introduce another method, for float, but then you'd have to have another for double, and long double... it's soon going to become difficult.

The simplest solution, is to go bruteforce:

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

For int and al, it's mostly useless but works. For floating points, we use the bigger floating point type available to avoid losing precision, and then perform the rounding.

Obviously, it does not quite work if suddenly we want a Point<float>, therefore we need a smarter solution, based on type traits. The class std::numeric_limits<T> has a is_integer which precises whether or not we are dealing with an integral type.

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

I know it seems stupid to use a if for something that could be determined at compile-time... but don't worry, the compiler is smart enough to do figure it out at compile-time and optimize away the if and the unused branch altogether ;)

七婞 2024-10-26 18:21:10

使用 boost enable_if 来防止在使用 float 实例化时使用 float 版本。

Use boost enable_if to prevent the float version when instanciated with float.

拧巴小姐 2024-10-26 18:21:10

你最好的选择是:

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

your best bet is:

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 ...);
};
—━☆沉默づ 2024-10-26 18:21:10

尽量不要在类中提供 Set() 的默认实现。这样,就更容易专注于浮动。

Try not to provide the default implementation of Set() inside the class. That way, it's easier to specialize for float.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文