假设我们有Matrix4类(矩阵四乘四)。
该类的用户经常希望用单位矩阵初始化Matrix4类型的变量。
我知道有两种选择:
为该类提供更改* this值的成员函数SetAsIdentity。所以用户会做这样的事情:
Mat4 m;
m.SetAsIdentity();
提供返回静态const单位矩阵的静态成员(或非成员)函数,如下所示(请参阅更新):
static Mat4 Mat4::Identity()
{
static const Mat4 m{ 1, 0, 0, 0, 0, 1, 0, 0,
0, 0, 1, 0, 0, 0, 0, 1 };
return m;
}
然后像这样使用它:
Mat4 m = Mat4::Identity();
在我看来,我想使用2个以上只是因为它可以在一行代码中使用。 有没有更好的方法来初始化矩阵,但仍然使用默认默认构造函数(最初的原因是让类保持POD)?可以用constexpr实现2号吗?速差,如果有的话?
更新
要求:
一条评论(由juanchopanza提出)建议使用虚拟类型:
class Mat4
{
public:
struct SIdentity {};
float f[16];
Mat4() = default;
Mat4(SIdentity) : f{ 1, 0, 0, 0 , 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}
{}
};
并初始化它:
Mat4 m(Mat4::SIdentity{});
似乎(?)更优雅(虽然它需要笨拙的实例化,变量会被优化掉吗?)
UPDATE2:
一条评论(由geza提出)建议将SIdentity ctor作为constexpr ctor。这增加了能够进行(静态)常量初始化和编译时初始化/构建的好处
答案 0 :(得分:2)
您的问题的答案是没有理由使用到目前为止提供的任何技术。
constexpr
。因此,对于constexpr可构造类型来说,这仍然是一个糟糕的选择。另一种方法是使用constexpr static global。我根本不理解与POD的冲突。将类构造为特殊值的最简单方法是简单地使静态函数按值返回(不使用静态局部)。以下似乎满足您的所有要求。
#include <array>
#include <type_traits>
struct MatrixFour {
MatrixFour() = default;
constexpr MatrixFour(const std::array<double, 16> x) : m_data(x) {}
static constexpr MatrixFour makeIdentity() {
return MatrixFour({1,0,0,0,
0,1,0,0,
0,0,1,0,
0,0,0,1});
}
private:
std::array<double, 16> m_data;
};
int main() {
static_assert(std::is_pod<MatrixFour>::value, "");
constexpr auto x = MatrixFour::makeIdentity();
return 0;
}
答案 1 :(得分:1)
如果您不关心默认情况下将Matrix
初始化为单位矩阵,您可以简单地编写类似这样的内容(简化数据结构)。在这里,每个MatrixPOD
首先都是一个单位矩阵,直到您将值更改为其他值或添加覆盖x
的初始值的其他构造函数:
struct MatrixPOD {
public:
int x[4] = { 0,0,0,1 };
MatrixPOD() { };
};
MatrixPOD gi; // identity matrix, even at file scope
如果您可以使用普通数据结构,您还可以提供用于初始化的宏,例如:
struct MatrixPOD2 {
public:
int x[4];
#define IDENTITY { 0,0,0,1 }
};
MatrixPOD2 gi2 = IDENTITY;
但是,如果您希望拥有一个包含更多构造函数的类,并且如果您希望仅在明确声明时进行“预初始化”,那么您可以引入一个全局标识实例,然后使用该实例初始化其他矩阵对象。请参阅以下代码,其中私有构造函数用于初始化此全局标识实例:
struct Matrix {
public:
int x[4];
Matrix() = default;
const static Matrix identity;
private:
Matrix(bool identity) {
if (identity)
memcpy (x,x_identity,sizeof(x));
};
const static int x_identity[4];
};
const Matrix Matrix::identity(true);
const int Matrix::x_identity[4] = { 0,0,0,1 };
int main() {
MatrixPOD p; // always an identity matrix
Matrix m; // not an identity matrix
Matrix mi = Matrix::identity; // identity matrix since explicitly assigned
return 0;
}