【问题标题】:C++ templates - partial specialisation of member functionC++ 模板 - 成员函数的部分特化
【发布时间】:2012-12-15 09:01:06
【问题描述】:

我正在尝试根据模板参数指定的 2D 或 3D 专门化一些几何函数。最好为问题的玩具版本包含一些(非常损坏的)代码:

template <typename T, int d>
class Point
{
public:
    int x;
    int y;
    int z;

    T add ()
    {
        return T(0);
    }

    template <>
    T add <T, 2> ()
    {
        return x + y;
    }

    template <>
    T add <T, 3> ()
    {
        return x + y + z;
    }
};

这段代码编译失败。我已经尝试了很多不同的模板参数格式和类定义的组合,但找不到一种方法来对 'd' 进行函数专业化,同时保留 'T' 通用。

在我的实际解决方案中,我尝试计算梯度、曲率、插值等,专门用于 2D 或 3D 案例。有些事情,比如梯度计算,可以简单地使用 'd' 参数来限制 for 循环迭代。其他的,比如插值,需要单独的 2D 和 3D 函数。

非常感谢任何提示!

【问题讨论】:

  • 模板参数T是干什么用的?它应该是您坐标的类型吗?如果是这样,为什么将 x,y,z 声明为 int 而不是 T 类型?
  • 只是为了澄清这一点:没有“模板专业化”之类的东西,您想要的是“模板重载”。
  • @Vaughn:这个简单的玩具问题源于我需要一个 2D 或 3D 网格,它可以在每个网格点包含任意类型(尽管通常只是 int、float 或 double)。因此 x,y(,z) 作为坐标,T 作为该坐标处的值类型。

标签: c++ class templates inheritance specialization


【解决方案1】:

我会建议这个解决方案:

template <typename T, int d> 
class Point : public Point<T, d-1>
{
   typedef Point<T, d-1> base;
   T m_value;
public:
    T add()
    {
        return m_value + base::add();
    }   

    //another method which returns you the point value
    template<int N>
    T get()
    {
       return N==d ? m_value : base::get<N>();
    }
};

template <typename T>
class Point<T,0>
{
protected:
    T add()
    {
        return T(); //default value which is zero for all builtin types
    }
    template<int N>
    T get() { return T(); }

};

使用此解决方案,您可以获得任意数量的点,但要大于zero

Point<int,1> p1;  //contains 1 point
Point<int,2> p2;  //contains 2 points
Point<int,3> p3;  //contains 3 points
Point<int,4> p4;  //contains 4 points
Point<int,5> p5;  //contains 5 points

auto x1 = p5.get<1>(); //get first point
auto x3 = p5.get<3>(); //get third point
auto x4 = p5.get<4>(); //get fourth point

或者为了方便使用这些类型定义:

typedef Point<int,2> Point2D;
typedef Point<int,3> Point3D;

//then use them
Point2D p2d;
Point3D p3d;

这只是一个基本概念,可以进一步增强,支持许多有用的功能。我刚刚写了get&lt;&gt; 来演示一个似乎有用的功能。

【讨论】:

  • 更好的方法。唯一的缺点是成员的有意义的名称松散。
  • @K-ballo:但那是实现细节!
  • @K-ballo:您始终可以使用 enable_if 有条件地将getX()getY()、...添加到d==1d==2、...
  • @Ben Jackson:你不能用enable_if 条件getX(),因为那里没有模板参数。如果我们这样做,那么我更喜欢get&lt;0&gt;
  • 哈哈,我喜欢这个,很巧妙!它从我上面的玩具问题中解决了我非常特殊的情况。将我的问题简化为玩具问题的想法只是强调一个事实,即我不知道如何对单个模板参数进行成员函数专业化,同时保持其他参数通用。 Vaughn 的解决方案更接近我真正想要的,只是它需要专门化整个类,而不仅仅是几个函数。
【解决方案2】:

这是您的示例的工作方式。您首先声明您的主模板:

template <typename T, int d> class Point;

没有必要定义它,因为你没有通用的实现。

接下来,您为不同数量的维度创建偏特化,但您的偏特化仍将类型 T 作为模板参数:

template <typename T>
class Point<T,2>
{
public:
    T x;
    T y;

    T add()
    {
        return x + y;
    }
};

template <typename T>
class Point<T,3>
{
public:
    T x;
    T y;
    T z;

    T add()
    {
        return x + y + z;
    }
};

【讨论】:

  • 好的,唯一的问题是,如果我想在专用(或覆盖)功能的同时拥有通用功能,我该怎么做?当只有几个功能实际上不同时,我不想专门化整个课程。
  • @Dave:一种方法是创建一个派生类,该类具有非特化的泛型函数,并从具有特化的基类继承。
  • 我怀疑我可能不得不求助于子类化而不是模板专业化。好的,那么,我想我有我的答案了。
猜你喜欢
  • 1970-01-01
  • 2013-02-28
  • 1970-01-01
  • 1970-01-01
  • 2012-04-11
  • 1970-01-01
  • 1970-01-01
  • 2013-09-24
相关资源
最近更新 更多