模板化变量

5

我目前拥有以下非模板化的代码:

class Vector{ 
  public:
    double data[3];
 };
static Vector *myVariable;
void func() {
  myVariable->data[0] = 0.;
}
int main() {
  myVariable = new Vector();
  func();
}

我接下来希望对尺寸进行模板化处理:
template<int DIM> class Vector{ 
  public:
    double data[DIM];
 };
static Vector<3>* myVariable;
void func() {
  myVariable->data[0] = 0.;
}
int main() {
  myVariable = new Vector<3>();
  func();
}

但是最终我也想将我的变量作为模板,并加上维度:

template<int DIM> class Vector{ 
  public:
    double data[DIM];
 };
template<int DIM> static Vector<DIM> *myVariable;

void func() {
  myVariable->data[0] = 0.;
  // or perform any other operation on myVariable
}
int main() {
  int dim = 3; 

  if (dim==3)
    myVariable = new Vector<3>();
  else
    myVariable = new Vector<4>();

  func();
}

然而,代码的最新版本出现了错误:这个静态变量无法被模板化(“C2998: Vector *myVariable不能是模板定义”)。
如何在不进行完全重新设计的情况下纠正此错误(比如从非模板类继承模板化的Vector类,这将需要更昂贵的调用虚方法,或手动创建几个不同维度的myVariables)?也许我只是累了,没有看到一个明显的答案:s
编辑:请注意,这段代码是一个最小化的工作代码,用来显示错误,但我的实际实现将维度模板化为一个完整的计算几何类,因此我不能仅仅用数组替换Vector。我看不出有解决我的问题的方法。
谢谢!
5个回答

2
有一段时间了,我之前在模板声明中使用了常量。最终我选择了另一种方法,所以我不知道它是否最终能成为你的解决方案。我认为这里的问题是任何模板变量必须在编译时知道其模板参数。
在您的示例中,Vector <3> 和 Vector <4> 是不同的类型,不能赋给同一个变量。这就是为什么template static Vector* myVariable没有任何意义; 它没有可辨别的类型。

将 myVariable 声明为 Vector<any_big_number>,并将新创建的 Vector<3> 强制转换为这个类型 (Vector<any_big_number>*),这样做可行吗?在此特定示例中似乎可以,但在更一般的情况下呢? - nbonneel
请注意,我没有将它们分配给同一个变量:变量仅存储指针...它本可以是(void *)。实际上,那可能就是解决方案! - nbonneel
@WhitAngl 你必须记住,模板中的常量与类型非常相似...在代码中使用不同的模板参数组合会导致生成和编译不同的类。也许这是由于编译器对类的表示方式而“工作”,在这个简单的例子中这是有意义的。然而,这是*不正确的,我认为编译器应该在静态转换时捕获类型不匹配。 - Keith Layne
void* 看起来更有意义,但无论如何你都需要进行强制类型转换才能使用它...我认为可能需要使用 dynamic_cast,但我不确定。我认为采用不同的方法可能会更好,只是没有更多信息很难说哪种方法更好。 - Keith Layne

1
template<int DIM> static Vector<DIM> *myVariable;

这是语言规范不允许的。故事结束。

由于我不理解您代码的目的或想要实现什么,我无法建议任何比简单地建议尝试使用std::vector<T>更好的替代方案。这也是因为我不知道我能够重新设计您的代码以及您使用它的方式来使您的代码工作。


我从编译错误中理解了这一点。有什么最好的方法可以使用可编译的代码并且尽可能少地更改来获得相同的预期结果? - nbonneel
std::vector<> 在堆上分配内存,就像 new[] 一样。这是一个最小化的代码,展示了编译错误,但我的实际代码包含有一个完整的基于泰森多边形的类模板,带有维度,并且有成千上万行代码。这就是为什么我希望至少进行最少量的重新设计的原因... - nbonneel
@WhitAngl 如果有一种方法可以确保在堆栈上分配内存,我不知道...但我并不是很清楚。 - Keith Layne

0

我想我找到了!

template<int DIM> class Vector{ 
  public:
    double data[DIM];
 };
static void *myVariable;

template<int DIM>
void func() {
((Vector<DIM>*)myVariable)->data[0] = 0.;
  // or perform any other operation on myVariable
}
int main() {
  int dim = 3; 

  if (dim==3)
  {
    myVariable = (void*) new Vector<3>();
    func<3>();
  }
  else
  {
    myVariable = (void*) new Vector<4>();
    func<4>();
   }


}

0

Vector<3>Vector<4>是完全不同的类型,它们之间没有任何正式关系。从你的角度来看,它们表面上相似并不重要。

如果你想让它们在某种程度上等价,我们有一个名字叫做接口。

template <typename Scalar = float>
class BasicVector {
public:
    typedef Scalar * iterator;
    virtual ~ BasicVector () {}

    virtual size_t   size  () const = 0;
    virtual iterator begin ()       = 0;
    virtual iterator end   ()       = 0;
};

template <unsigned N, typename Scalar = float>
class Vector : public BasicVector <Scalar> {
    Scalar m_elements [N];
public:
    using Scalar :: iterator;
    size_t   size  () const {return N;}
    iterator begin ()       {return m_elements;}
    iterator end   ()       {return m_elements + N;}
};

int main () {
    BasicVector * a;
    a = new Vector <3>;
    a = new Vector <4>;
}

拥有一个超类需要虚拟方法调用的开销,对于那些可能被多次调用的函数来说,这可能会过于昂贵。:s - nbonneel
没错,但是除非你对 void* 和失去类型安全感到满意,否则这是完全必要的。 - spraff

0

您可以使用std::array来模板化维度,但是您不能将一个维度的指针强制转换为另一个维度的指针。


我的实际代码模板不是为一个向量类而是为整个几何计算类的维度设计的...我编辑了我的问题以使其更清晰。谢谢! - nbonneel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接