我有一堂课
template <unsigned int N>
class StaticVector {
// stuff
};
如何在此类中声明和定义返回 StaticVector<3> 对象的静态工厂方法,例如
StaticVector<3> create3dVec(double x1, double x2, double x2);
?
“我如何在这个类中声明和定义”
在什么班?您已经定义了一个类模板,而不是一个类。您不能调用类模板本身的静态函数,您必须调用作为真实类一部分的特定版本的静态函数。
那么,您希望模板(以及它的所有实例化)具有返回 StaticVector<3> 的函数,还是希望该模板的特定实例化具有返回 StaticVector<3> 的函数?
如果是前者:
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<3> 的成员,而不是所有 SV<whatever> 的成员),那么您需要模板专业化:
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 中那样需要静态函数:如果您想要一个“foo”函数为类 Bar 做一件事而为类 Baz 做另一件事,您可以将其声明为函数带有可以是 Bar 或 Baz 的模板参数的模板(可能从函数参数中推断出来,也可能不推断出来),而不是使其成为每个类的静态函数。但是如果你确实希望它是一个静态函数,那么你必须使用一个特定的类来调用它,而不仅仅是一个模板名称。
就像是 :
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 替换为基本数组,但使用原始数组需要您自担风险:)
首先,我相信你原本的意思是返回
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
就行不通了。您可以使用此处描述的技术来做到这一点。
如果您想让这样的函数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);
数组永远不能是空指针。当然,如果您愿意,您可以随时将数组参数更改为指针。这只是我个人的喜好:)
@litb
我想返回一个三元素向量。原因是这些向量应该是几何实体,所以不需要N太高(我不是弦物理学家,所以我不在11维空间工作)。我想创建一个模板以避免重复代码,但将 1 维、2 维和 3 维向量保留为单独的类型。