Factory方法返回C ++模板类的具体实例化

时间:2009-01-31 12:43:09

标签: c++ templates factory

我有一个班级

template <unsigned int N>
class StaticVector {
// stuff
};

如何在此类中声明并定义一个返回StaticVector&lt; 3&gt;的静态工厂方法。对象,像......

StaticVector<3> create3dVec(double x1, double x2, double x2);

4 个答案:

答案 0 :(得分:1)

“我如何在此课程中声明和定义”

在什么课上?您已经定义了一个类模板,而不是一个类。你不能调用类模板本身的静态函数,你必须调用属于真实类的静态函数的特定版本。

那么,您是否希望模板(以及它的所有实例化)都有一个返回StaticVector&lt; 3&gt;的函数,或者您是否希望该模板的一个特定实例具有返回StaticVector&lt; 3&gt;的函数?

如果是前者:


  template <unsigned int N>
  struct SV {
    int contents[N];
    static SV<3> get3dVec(int x, int y, int z) {
      SV<3> v;
      v.contents[0] = x;
      v.contents[1] = y;
      v.contents[2] = z;
      return v;
    }
  };

  int main() {
    SV<3> v = SV<1>::get3dVec(1,2,3);
  }

适合我。

如果是后者(你只想让get3dVec成为SV&lt; 3&gt;的成员,而不是所有的SV&lt; whatever&gt;),那么你需要模板专业化:


  template <unsigned int N>
  struct SV {
    int contents[N];
  };

  template<>
  struct SV<3> {
    int contents[3]; // must be re-declared in the specialization
    static SV<3> get3dVec(int x, int y, int z) {
      SV<3> v;
      v.contents[0] = x;
      v.contents[1] = y;
      v.contents[2] = z;
      return v;
    }
  };

  int main() {
    SV<3> v = SV<1>::get3dVec(1,2,3); // compile error
    SV<3> v = SV<3>::get3dVec(1,2,3); // OK
  }

如果除了通过省略基本上不相关的模板参数使调用代码看起来更好之外没有其他原因,我同意Iraimbilanja通常一个自由函数(如果你正在编写以供重用,则在命名空间中)会产生更多感觉这个例子。

C ++模板意味着你在C ++中不需要像在Java中那样需要静态函数:如果你想要一个为类Bar做一件事的“foo”函数和为类Baz做另一件事,你可以声明它作为具有模板参数的函数模板,模板参数可以是Bar或Baz(可以从函数参数推断也可以不推断),而不是在每个类上使其成为静态函数。但是如果你确实希望它是一个静态函数,那么你必须使用特定的类来调用它,而不仅仅是模板名称。

答案 1 :(得分:0)

类似的东西:

template< unsigned int SIZE >
StaticVector< SIZE > createVec( const std::tr1::array< double, SIZE >& values )
{ 
     StaticVector< SIZE > vector;
     for( int i = 0; i < values.size(); ++i ) // here assuming that StaticVector have [] operator to access values on write
     {
         vector[i] = values[i];
     }

     return vector;
}

......或者变体肯定会起作用。 (没试过)

用法是:

std::tr1::array< double, 3 > vectorValues = { 10.0, 10.0, 42.0 };

StaticVector<3> vector1 = createVector( vectorValues ); // if the compiler can guess the size from the array information
StaticVector<3> vector2 = createVector<3>( vectorValues ); // if you have to specify the size

另一种方法是用基本数组替换std :: tr1 :: array,但它会使用原始数组,风险自负:)

答案 2 :(得分:0)

首先,我相信你最初的意思是回归

StaticVector<N>

而不是总是N == 3的专业化。所以,你想要做的就是这样写:

template <unsigned int N>
class StaticVector {
public:
    // because of the injected class-name, we can refer to us using
    // StaticVector . That is, we don't need to name all template
    // parameters like StaticVector<N>.
    static StaticVector create3dVec(double x1, double x2, double x2) {
        // create a new, empty, StaticVector
        return StaticVector();
    }

};

如果您确实想要始终返回3dVector,您可能希望将其限制为N == 3,以便例如StaticVector<4>::create3dVec不起作用。您可以使用here描述的技术来实现这一目标。

如果你想拥有一个适用于任何大小的createVec函数,你可能想要用数组替换参数。你可以这样做,但这是先进的,需要使用boost :: preprocessor应用一些宏技巧。我认为这不值得。下一个C ++版本将为此提供可变参数模板。无论如何,考虑使用这样的东西:

我认为这只会让这种情况不必要地复杂化。一个快速的解决方案是使用boost :: fusion :: vector,将其放入类模板而不是上面的版本中:

static StaticVector createVec(double (&values)[N]) {
    // create a new, empty, StaticVector, initializing it
    // with the given array of N values.
    return StaticVector();
}

您可以将其与

一起使用
double values[3] = {1, 2, 3};
StaticVector<3> v = StaticVector<3>::createVec(values);

请注意,它通过引用接受数组。你不能给它一个指针。那是因为它匹配参数的使用:你也不能为其他方式提供更少或更多的参数。它还可以保护您免受以下情况的影响:

// oops, values is a null pointer!
StaticVector<3> v = StaticVector<3>::createVec(values);

数组永远不能是空指针。当然,如果您愿意,可以随时将数组参数更改为指针。这只是我个人的偏好:))

答案 3 :(得分:0)

@litb

我想返回一个3元素的向量。原因是这些向量应该是几何实体,因此不需要N太高(我不是一个字符串物理学家,因此我不在11维空间中工作)。我想创建一个模板,以避免重复代码,但保留1,2和3维向量作为单独的类型。