目前,我已经实现了一个模板类Mat,它是第三方库的矩阵类的包装器(T是组件的类型:double,int等)。现在,我希望实现Tensor类使用一个Mat进行存储,使用第二个Mat进行映射索引。
我将Tensor类模板化为Tensor,其中T与Mat类相同,Order和Dim是整数,是张量的阶数(或秩)和维数(2或3)。 Sym是对称性的布尔标志。
Tensor类将利用Voigt表示法将高阶张量压缩到矩阵上(例如,3乘3乘3乘3张量可以映射到6乘6矩阵;这是通过将每对索引映射到单个索引来完成的。在Voigt表示法中,3乘3张量可以映射到6乘1的向量(矩阵),但是将张量中的(0,0)分量移动到向量中的0位置。类似的(1,1) - > 1,(2,2) - > 2,(1,2) - > 3,(0,2) - > 4,和(0,1) - > 5.类似的规则退出2乘2张量(它们映射到3乘1矩阵)。
为此,我希望我的Tensor类拥有矩阵:
0 5 4
5 1 3
4 3 2
如果Dim == 3且Sym == true。对不对称张量和2D张量有相应的映射(总共4个)。这些不依赖于其他模板参数(T和Order)。
因此,我在什么时候专注于他们? (这里,该问题适用于任何具有模板类的人,只需要部分特化的静态const成员。)
我在这里查看了这个问题:Where to define static const member variables of a template class。但它并没有讨论部分专业化。
到目前为止,我在同一个头文件中有一个前向声明和一个类定义:
//cl_Tensor.hpp
namespace myNamespace
{
template< typename T, int Order, int Dim, bool Sym >
class Tensor;
}
template< typename T, int Order, int Dim, bool Sym >
class myNamespace::Tensor
{
protected:
myNamespace::Mat< T> mMat; // storage
static const myNamespace::Mat < uint > mTensorMap;
public:
// member functions and the like...
}
在我的Tensor类的单元测试中,我可以输入:
template<> const moris::Mat< moris::uint> moris::Tensor< moris::real, 1, 2, true>::mTensorMap = { { 0, 2}, {2, 1} };
template<> const moris::Mat< moris::uint> moris::Tensor< moris::real, 1, 2, false>::mTensorMap = { { 0, 3}, {2, 1} };
template<> const moris::Mat< moris::uint> moris::Tensor< moris::real, 1, 3, true>::mTensorMap = { { 0, 5, 4}, {5, 1, 3}, {4, 3, 2} };
template<> const moris::Mat< moris::uint> moris::Tensor< moris::real, 1, 3, false>::mTensorMap = { { 0, 5, 4}, {8, 1, 3}, {7, 6, 2} };
问题是我必须为每个订单(1,2,3和4)执行此操作。我应该有其他类型的张量(这里,真的是长双倍的typdef),我会有太多重复的代码。
我在哪里可以初始化地图呢?
答案 0 :(得分:2)
您不能部分地专门化类模板的静态数据成员,但您可以像在问题中所说的那样明确地对它们进行专门化。但是没有什么可以阻止你将定义外包给其他功能模板:
namespace myNamespace {
template< typename T, int Order, int Dim, bool Sym >
const Tensor<T, Order, Dim, bool>::Mat<Dim> mTensorMap =
TensorMapCreator<T, Order, Dim, Sym>::makeMap();
}
然后,只需创建一个带有静态成员函数TensorMapCreator
的类模板makeMap()
,您可以根据自己特别想要的内容进行部分专门化:
template <typename T, int Order, int Dim, bool Sym>
struct TensorMapCreator;
template <typename T, int Order, bool Sym>
struct TensorMapCreator<T, Order, 2, Sym> {
static Mat<2> makeMap();
};
template <typename T, int Order, bool Sym>
struct TensorMapCreator<T, Order, 3, Sym> {
static Mat<3> makeMap();
};
// etc.
答案 1 :(得分:0)
我能够取消另一个答案并提出以下解决方案。在Tensor头文件中,我只在类定义中声明了静态const。然后,我使用MapCreator类模拟成员初始化。
//Tensor.hpp
template< typename T, int Order, int Dim, bool Sym >
class space::Tensor
{
protected:
Mat< T> mStorageMat;
static const Mat < unsigned int > mTensorMap;
public:
// ...
};
template< typename T, int Order, int Dim, bool Sym >
const space::Mat< unsigned int> space::Tensor<T, Order, Dim, Sym>::mTensorMatp = space::TensorMapCreator< Dim, Sym>::makeMap();
然后,TensorMapCreator类仅模仿我的成员变量所依赖的两个参数:
//TensorMapCreator.hpp
namespace space {
template< int Dim, bool Sym>
class TensorMapCreator;
class TensorMapCreator< 2, true >; // specialized forward
class TensorMapCreator< 2, false>; // declarations
class TensorMapCreator< 3, true >;
class TensorMapCreator< 3, false>;
}
class space::TensorMapCreator< 2, true >
{
public:
static
space::Mat< unsigned int>
makeMap()
{
// creates the correct map
}
};
// 3 more specializations for the other
// combinations of dimmension and symmetry