【问题标题】:templated variable模板变量
【发布时间】:2011-09-22 16:52:53
【问题描述】:

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

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 cannot be a template definition”)。

如果没有完全重新设计,我怎么可能纠正这个错误(比如从非模板类继承模板化 Vector 类,这将需要对虚拟方法进行更昂贵的调用,或者手动创建多个不同维度的 myVariables)?也许我只是累了,没有看到明显的答案:s

编辑:请注意,此代码是显示错误的最小工作代码,但我的实际实现模板化了完整计算几何类的维度,因此我不能只用数组替换 Vector。我发现我的问题似乎没有解决方案。

谢谢!

【问题讨论】:

    标签: c++ templates


    【解决方案1】:

    已经有一段时间了,但我以前在模板声明中使用过常量。我最终朝着另一个方向发展,所以我也不知道它最终是否会成为你的解决方案。我认为这里的问题是任何模板化变量都必须在编译时知道它的模板参数。

    在您的示例中,Vector&lt;3&gt;Vector&lt;4&gt; 是不同的类型,不能分配给同一个变量。这就是为什么template&lt;int DIM&gt; static Vector&lt;DIM&gt; *myVariable 没有任何意义;它没有可辨别的类型。

    【讨论】:

    • 是否将 myVariable 声明为 Vector 并将新的 Vector 转换为 (Vector*) 工作?它似乎在这个特定示例中有效,但在更一般的情况下......?
    • 请注意,我没有将它们分配给同一个变量:该变量仅存储一个指针......它可能是一个 (void*)。实际上,这可能是解决方案!
    • @WhitAngl 您必须记住,模板中的常量与类型非常相似……代码中使用的模板参数的每种不同组合都会导致生成和编译不同的类。由于编译器对类的表示,它可能“有效”,并且在这个简单的示例中是有道理的。但是,它是正确的,编译器应该在我认为的静态转换上捕获类型不匹配。
    • void* 几乎更有意义,但无论你必须投什么才能使用它......我认为它需要一个 dynamic_cast 但我不确定。我认为另一种方法可能会更好,如果没有更多信息,很难说哪个方法。
    【解决方案2】:
    template<int DIM> static Vector<DIM> *myVariable;
    

    语言规范不允许这样做。故事结束。

    而且由于我不了解您的代码的目的或您想要实现的目标,因此我无法提出比简单地建议尝试使用更好的替代方案std::vector&lt;T&gt;。这也是因为我不知道我可以在多大程度上重新设计您的代码,以及您使用它的方式,以使您的代码正常工作。

    【讨论】:

    • 我从编译错误中了解到这一点。使用可编译的代码和最少的更改获得相同预期结果的最佳方法是什么?
    • std::vector 像 new[] 一样在堆上分配内存。这是显示编译错误的最小代码,但我的实际代码有一个以维度为模板的整个 voronoi 图类,并且有数千行长。这就是为什么我希望至少进行最少的重新设计......
    • @WhitAngl 如果有办法确保在堆栈上分配内存我不知道......但我知道的不多。
    【解决方案3】:

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

    【讨论】:

    • 我的实际代码模板的维度不是 Vector 类,而是整个几何计算类......我编辑我的问题以使其更清晰。谢谢!
    【解决方案4】:

    我想我找到了!

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

    【讨论】:

      【解决方案5】:

      Vector&lt;3&gt;Vector&lt;4&gt;完全不同的类型,并且彼此之间没有正式关系。从您的角度来看,它们表面上相似这一事实并不重要。

      如果您希望它们与某种类型等效,我们有一个名称:interfaces

      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
      • 没错,但除非您对 void* 感到满意并失去类型安全性,否则这是完全必要的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-05
      • 2015-05-25
      • 2015-05-20
      • 2012-11-17
      • 2018-10-12
      • 2013-03-05
      相关资源
      最近更新 更多