C++ c+中的静态公共值函数+;

C++ c+中的静态公共值函数+;,c++,c++11,C++,C++11,假设我们有Matrix4类(矩阵四乘四) 此类的用户通常希望使用标识矩阵初始化Matrix4类型的变量 我知道有两种选择: 为更改*this值的类提供成员函数SetAsIdentity。所以用户会这样做: Mat4 m; m.SetAsIdentity(); 提供返回静态常量标识矩阵的静态成员(或非成员)函数,类似于以下内容(请参见更新): 然后像这样使用它: Mat4 m = Mat4::Identity(); 在我看来,我希望使用2多于1,因为它可以在一行代码中使用。 是否有更好的方

假设我们有Matrix4类(矩阵四乘四)

此类的用户通常希望使用标识矩阵初始化Matrix4类型的变量

我知道有两种选择:

  • 为更改*this值的类提供成员函数SetAsIdentity。所以用户会这样做:

    Mat4 m;
    m.SetAsIdentity();
    
  • 提供返回静态常量标识矩阵的静态成员(或非成员)函数,类似于以下内容(请参见更新):

    然后像这样使用它:

    Mat4 m = Mat4::Identity();
    
  • 在我看来,我希望使用2多于1,因为它可以在一行代码中使用。 是否有更好的方法来初始化矩阵,但仍然使用默认的默认构造函数(最初的原因是使类保持POD)?2号可以用constexpr实现吗?速度差,如果有的话

    更新:

    要求:

    • 默认值为默认值
    • 必须能够定义非默认ctor(2实际上不符合此要求。它在msvc上编译,但在gcc或clang上编译)
    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{});
    
    哪一个看起来更优雅(尽管它需要笨拙的实例化,变量会被优化掉吗?)

    更新2:


    geza的一条评论建议将SIdentity作为constexpr。这增加了能够进行(静态)常量初始化和编译时初始化/构造的好处

    如果您不关心您的
    矩阵
    在默认情况下将被初始化为标识矩阵,那么您可以简单地编写如下内容(简化的数据结构)。在这里,每个
    矩阵pod
    首先将是一个单位矩阵,直到您将值更改为其他值或添加覆盖
    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;
    }
    

    如果您不关心您的
    矩阵
    在默认情况下会被初始化为标识矩阵,那么您可以简单地编写如下内容(简化的数据结构)。在这里,每个
    矩阵pod
    首先将是一个单位矩阵,直到您将值更改为其他值或添加覆盖
    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;
    }
    

    你的问题的答案是没有理由使用到目前为止介绍的任何技术

  • 不要使用构造后调用的变异函数。这很难看,因为它是两行而不是一行,更糟糕的是,您失去了生成值const或constexpr的机会
  • 不要对可以成为constexpr的构造函数使用静态本地。编辑:尽管在这种情况下没有真正的性能影响(正如我之前错误地写的那样),但是具有静态本地的函数不能是
    constexpr
    。因此,对于constexpr可构造类型来说,这仍然是一个糟糕的选择。另一种方法是使用constexpr静态全局变量
  • 没有任何理由求助于像向构造函数中输入标记类型这样的黑客行为
  • 我真的一点也不理解与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;
    }
    
    #包括
    #包括
    结构矩阵四{
    MatrixFour()=默认值;
    constexpr MatrixFour(const std::array x):m_data(x){}
    静态constexpr矩阵四个makeIdentity(){
    返回矩阵四({1,0,0,0,
    0,1,0,0,
    0,0,1,0,
    0,0,0,1});
    }
    私人:
    std::数组m_数据;
    };
    int main(){
    静态断言(std::is_pod::value,“”);
    constexpr auto x=MatrixFour::makeIdentity();
    返回0;
    }
    
    您的问题的答案是,没有理由使用目前介绍的任何技术

  • 不要使用构造后调用的变异函数。这很难看,因为它是两行而不是一行,更糟糕的是,您失去了生成值const或constexpr的机会
  • 不要对可以成为constexpr的构造函数使用静态本地。编辑:尽管在这种情况下没有真正的性能影响(正如我之前错误地写的那样),但是具有静态本地的函数不能是
    constexpr
    。因此,对于constexpr可构造类型来说,这仍然是一个糟糕的选择。另一种方法是使用constexpr静态全局变量
  • 没有任何理由求助于像向构造函数中输入标记类型这样的黑客行为
  • 我真的一点也不理解与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;
    }
    
    #包括
    #包括
    结构矩阵四{
    MatrixFour()=默认值;
    constexpr MatrixFour(const std::array x):m_data(x){}