在构造函数上使用已删除函数的联合使用的类

class with union use of deleted function on constructor

本文关键字:函数 构造函数 删除      更新时间:2023-10-16

我正在尝试制作一个4*4矩阵的类对于每一列)。问题是它不会编译,并且无论我在哪里称为Mat4的构造函数。
我的mat4.h:

struct mat4 {
    union
    {
        float elements[4 * 4]; // column major ordering, index = row + col * 4
        vec4 columns[4];
    };
    mat4();
    mat4(float diagonal);
    mat4& mul(const mat4& other); //TODO: maybe return mat4
   // vec4 getColumn(int colIndex);
    static mat4 identity(); // construct and return an identity matrix
    static mat4 orthographic(float left, float right, float bottom, float top, float near, float far); // boundaries (clipping planes)
    static mat4 perspective(float fov, float aspectRatio, float near, float far);
    static mat4 translation(const vec3& translation);
    static mat4 scale(const vec3 &scale);
    static mat4 rotation(float angle, const vec3 & axis);
    friend mat4 operator*(mat4 left, const mat4 & right);
    mat4& operator*=(const mat4 &other); //TODO: check that it fits with the vectors
    friend std::ostream &operator<<(std::ostream &stream, const mat4 &m);
};

我的mat4.cpp:

#include "mat4.h"
        mat4::mat4() {
            for (int i = 0; i < 4 * 4; i++)
                elements[i] = 0;
        }
        mat4::mat4(float diagonal) {
            for (int i = 0; i < 4 * 4; ++i) {
                elements[i] = 0;
            }
            for(int i = 0; i < 4; i += 1)
                elements[i + i * 4] = diagonal;
        }
        mat4& mat4::mul(const mat4 &other) {
            for (int i = 0; i < 4; ++i)        // col
                for (int j = 0; j < 4; ++j) {  // row
                    float sum = 0;
                    for (int k = 0; k < 4; ++k)
                        sum += elements[j + k * 4] * other.elements[k + i * 4];
                    elements[j + i * 4] = sum;
                }
            return *this;
        }
        /*vec4 mat4::getColumn(int colIndex) {
            //colIndex *= 4; // TODO: profile and see if it's the same as (colIndex * 4) in each cell
            return vec4(elements[0 + colIndex * 4], elements[1 + colIndex * 4], elements[2 + colIndex * 4], elements[3 + colIndex * 4]);
        }*/
        mat4 mat4::identity() {
            return mat4(1.0f);
        }
        mat4 operator*(mat4 left, const mat4 &right) {
            return left.mul(right);
        }
        mat4 &mat4::operator*=(const mat4 &other) {
            return mul(other);
        }
        mat4 mat4::orthographic(float left, float right, float bottom, float top, float near, float far) {
            mat4 result(1);
            result.elements[0 + 0 * 4] =  2.0f / (right - left);
            result.elements[1 + 1 * 4] =  2.0f / (top - bottom);
            result.elements[2 + 2 * 4] = -2.0f / (far - near);
            result.elements[0 + 3 * 4] = (left + right) / (left - right);
            result.elements[1 + 3 * 4] = (bottom + top) / (bottom - top);
            result.elements[2 + 3 * 4] = (far + near)   / (far - near);
            //result.elements[3 + 3 * 4] = 1; this is achieved by mat result(1);
            return result;
        }
        mat4 mat4::perspective(float fov, float aspectRatio, float near, float far) {
            mat4 result;
            float q = 1.0f / tanf(toRadians(fov) / 2.0f);
            result.elements[0 + 0 * 4] = q / aspectRatio;
            result.elements[1 + 1 * 4] = q;
            result.elements[2 + 2 * 4] = (near + far) / (near - far);   // -(far + near)  / (far - near);
            result.elements[3 + 2 * 4] = -1;
            result.elements[2 + 3 * 4] = 2 * far * near / (near - far); // -2 * far * near / (far - near);
            return result;
        }
        mat4 mat4::translation(const vec3 &translation) {
            mat4 result(1.0f); // identity matrix
            result.elements[0 + 3 * 4] = translation.x;     // create a matrix as follows: 1 0 0 x
            result.elements[1 + 3 * 4] = translation.y;     //                             0 1 0 y
            result.elements[2 + 3 * 4] = translation.z;     //                             0 0 1 z
            return result;                                  //                             0 0 0 1
        }
        mat4 mat4::scale(const vec3 &scale) {
            mat4 result(1.0f);
            result.elements[0 + 0 * 4] = scale.x;     // create a matrix as follows: x 0 0 0
            result.elements[1 + 1 * 4] = scale.y;     //                             0 y 0 0
            result.elements[2 + 2 * 4] = scale.z;     //                             0 0 z 0
            return result;                            //                             0 0 0 1
        }
        mat4 mat4::rotation(float angle, const vec3 &axis) {
            mat4 result(1.0f);
            float r = toRadians(angle);
            float s = sinf(r);
            float c = cosf(r);
            result.elements[0 + 0 * 4] = axis.x * (1 - c) + c;
            result.elements[1 + 0 * 4] = axis.x * axis.y * (1 - c) + axis.z * s;
            result.elements[2 + 0 * 4] = axis.x * axis.z * (1 - c) - axis.y * s;
            result.elements[0 + 1 * 4] = axis.y * axis.x * (1 - c) - axis.z * s;
            result.elements[1 + 1 * 4] = axis.y * (1 - c) + c;
            result.elements[2 + 1 * 4] = axis.y * axis.z * (1 - c) + axis.x * s;
            result.elements[0 + 2 * 4] = axis.z * axis.x * (1 - c) + axis.y * s;
            result.elements[1 + 2 * 4] = axis.z * axis.y * (1 - c) - axis.x * s;
            result.elements[2 + 2 * 4] = axis.z * (1 - c) + c;
            return result;
        }
        std::ostream &operator<<(std::ostream &stream, const mat4 &m) {
            stream << "mat4: ( ";
            for (int i = 0; i < 4; ++i) {
                for (int j = 0; j < 4; ++j) {
                    stream << m.elements[i + j * 4] << " ";
                }
                if(i < 3) stream << std::endl << "        ";
                else stream << ")";
            }
            return stream;
        }

我的vec4.h:

#include <iostream>
        struct vec4 {
            float w, x, y, z;
            vec4() = default; // declare a default constructor as a no-parameter constructor (given that I have another one)
            vec4(float w, float x, float y, float z);
            vec4(const vec4 &v);
            vec4 add(const vec4 &other); 
            vec4 add(float w, float x, float y, float z); 
            vec4 sub(const vec4 &other); 
            vec4 sub(float w, float x, float y, float z); 
            vec4 mul(const vec4 &other); 
            vec4 mul(float w, float x, float y, float z); 
            vec4 div(const vec4 &other); 
            vec4 div(float w, float x, float y, float z); 
            friend vec4 operator+(vec4 left, const vec4 &right);
            friend vec4 operator-(vec4 left, const vec4 &right);
            friend vec4 operator*(vec4 left, const vec4 &right);
            friend vec4 operator/(vec4 left, const vec4 &right);
            vec4 operator+=(const vec4 &other);
            vec4 operator-=(const vec4 &other);
            vec4 operator*=(const vec4 &other);
            vec4 operator/=(const vec4 &other);
            bool operator==(const vec4 &other);
            bool operator!=(const vec4 &other);
            friend std::ostream &operator<<(std::ostream &stream, const vec4 &vector);
        };

我的vec4.cpp:

/*     vec4::vec4() {
            w = 0;
            x = 0;
            y = 0;
            z = 0;
        }
*/
        vec4::vec4(float w, float x, float y, float z) {
            this->w = w;
            this->x = x;
            this->y = y;
            this->z = z;
        }
        vec4::vec4(const vec4 &v) {
            this->w = v.w;
            this->x = v.x;
            this->y = v.y;
            this->z = v.z;
        }
        vec4 vec4::add(const vec4 &other) {
            this->w += other.w;
            this->x += other.x;
            this->y += other.y;
            this->z += other.z;
            return *this;
        }
        vec4 vec4::add(float w, float x, float y, float z) {
            this->w += w;
            this->x += x;
            this->y += y;
            this->z += z;
            return *this;
        }
        vec4 vec4::sub(const vec4 &other) {
            this->w -= other.w;
            this->x -= other.x;
            this->y -= other.y;
            this->z -= other.z;
            return *this;
        }
        vec4 vec4::sub(float w, float x, float y, float z) {
            this->w -= w;
            this->x -= x;
            this->y -= y;
            this->z -= z;
            return *this;
        }
        vec4 vec4::mul(const vec4 &other) {
            this->w *= other.w;
            this->x *= other.x;
            this->y *= other.y;
            this->z *= other.z;
            return *this;
        }
        vec4 vec4::mul(float w, float x, float y, float z) {
            this->w *= w;
            this->x *= x;
            this->y *= y;
            this->z *= z;
            return *this;
        }
        vec4 vec4::div(const vec4 &other) {
            this->w /= other.w;
            this->x /= other.x;
            this->y /= other.y;
            this->z /= other.z;
            return *this;
        }
        vec4 vec4::div(float w, float x, float y, float z) {
            this->w /= w;
            this->x /= x;
            this->y /= y;
            this->z /= z;
            return *this;
        }
        std::ostream &operator<<(std::ostream &stream, const vec4 &vector) {
            stream << "vec4: (" << vector.w << ", " << vector.x << ", " << vector.y << ", " << vector.z << ")";
            return stream;
        }
        vec4 operator+(vec4 left, const vec4 &right) {
            return left.add(right);
        }
        vec4 operator-(vec4 left, const vec4 &right) {
            return left.sub(right);
        }
        vec4 operator*(vec4 left, const vec4 &right) {
            return left.mul(right);
        }
        vec4 operator/(vec4 left, const vec4 &right) {
            return left.div(right);
        }
        vec4 vec4::operator+=(const vec4 &other) {
            return add(other);
        }
        vec4 vec4::operator-=(const vec4 &other) {
            return sub(other);
        }
        vec4 vec4::operator*=(const vec4 &other) {
            return mul(other);
        }
        vec4 vec4::operator/=(const vec4 &other) {
            return div(other);
        }
        bool vec4::operator==(const vec4 &other) {
            return (this->w == other.w && this->x == other.x && this->y == other.y && this->z == other.z);
        }
        bool vec4::operator!=(const vec4 &other) {
            return !(*this == other);
        }

和错误日志:

.../src/math/mat4.cpp: In static member function ‘static engine::math::mat4 engine::math::mat4::identity()’:
.../src/math/mat4.cpp:36:29: error: use of deleted function ‘engine::math::mat4::mat4(engine::math::mat4&&)’
             return mat4(1.0f);
                             ^
In file included from .../src/math/mat4.cpp:5:0:
.../src/math/mat4.h:11:16: note: ‘engine::math::mat4::mat4(engine::math::mat4&&)’ is implicitly deleted because the default definition would be ill-formed:
         struct mat4 {
                ^
.../src/math/mat4.h:16:31: error: union member ‘engine::math::mat4::<anonymous union>::columns’ with non-trivial ‘engine::math::vec4::vec4(const engine::math::vec4&)’
                 vec4 columns[4];
                               ^
.../src/math/mat4.cpp: In function ‘engine::math::mat4 engine::math::operator*(engine::math::mat4, const engine::math::mat4&)’:
.../src/math/mat4.cpp:40:34: error: use of deleted function ‘engine::math::mat4::mat4(const engine::math::mat4&)’
             return left.mul(right);
                                  ^
In file included from .../src/math/mat4.cpp:5:0:
.../src/math/mat4.h:11:16: note: ‘engine::math::mat4::mat4(const engine::math::mat4&)’ is implicitly deleted because the default definition would be ill-formed:
         struct mat4 {
                ^
.../src/math/mat4.h:16:31: error: union member ‘engine::math::mat4::<anonymous union>::columns’ with non-trivial ‘engine::math::vec4::vec4(const engine::math::vec4&)’
                 vec4 columns[4];
                               ^
.../src/math/mat4.cpp: In static member function ‘static engine::math::mat4 engine::math::mat4::orthographic(float, float, float, float, float, float)’:
.../src/math/mat4.cpp:56:20: error: use of deleted function ‘engine::math::mat4::mat4(engine::math::mat4&&)’
             return result;
                    ^
.../src/math/mat4.cpp: In static member function ‘static engine::math::mat4 engine::math::mat4::perspective(float, float, float, float)’:
.../src/math/mat4.cpp:69:20: error: use of deleted function ‘engine::math::mat4::mat4(engine::math::mat4&&)’
             return result;
                    ^
.../src/math/mat4.cpp: In static member function ‘static engine::math::mat4 engine::math::mat4::translation(const engine::math::vec3&)’:
.../src/math/mat4.cpp:77:20: error: use of deleted function ‘engine::math::mat4::mat4(engine::math::mat4&&)’
             return result;                                  //                             0 0 0 1
                    ^
.../src/math/mat4.cpp: In static member function ‘static engine::math::mat4 engine::math::mat4::scale(const engine::math::vec3&)’:
.../src/math/mat4.cpp:85:20: error: use of deleted function ‘engine::math::mat4::mat4(engine::math::mat4&&)’
             return result;                            //                             0 0 0 1
                    ^
.../src/math/mat4.cpp: In static member function ‘static engine::math::mat4 engine::math::mat4::rotation(float, const engine::math::vec3&)’:
.../src/math/mat4.cpp:105:20: error: use of deleted function ‘engine::math::mat4::mat4(engine::math::mat4&&)’
             return result;
                    ^
CMakeFiles/GameEngine.dir/build.make:169: recipe for target 'CMakeFiles/GameEngine.dir/src/math/mat4.cpp.o' failed
make[3]: *** [CMakeFiles/GameEngine.dir/src/math/mat4.cpp.o] Error 1
make[3]: *** Waiting for unfinished jobs....
.../main.cpp: In function ‘int main(int, char**)’:
.../main.cpp:19:50: error: use of deleted function ‘engine::math::mat4::mat4(engine::math::mat4&&)’
     mat4 position = mat4::translation(vec3(2,3,4));
                                                  ^
In file included from .../src/math/math.h:8:0,
                 from .../main.cpp:4:
.../src/math/mat4.h:11:16: note: ‘engine::math::mat4::mat4(engine::math::mat4&&)’ is implicitly deleted because the default definition would be ill-formed:
         struct mat4 {
                ^
.../src/math/mat4.h:16:31: error: union member ‘engine::math::mat4::<anonymous union>::columns’ with non-trivial ‘engine::math::vec4::vec4(const engine::math::vec4&)’
                 vec4 columns[4];
                               ^

我认为大多数代码都是无关紧要的,所以不要打扰阅读所有代码。只是为了比较,如果我从Mat4.H的联盟中删除链接vec4 columns[4];,那么一切都很棒。

过去一个小时我一直在为此打破头脑,所以我真的很想要一些帮助。

谢谢。

编辑:

尝试了 @0x499602d2建议的内容,并将mat4(mat4&&) = default;添加到Mat4.h,我只剩下一个错误:

.../src/math/mat4.cpp: In function ‘engine::math::mat4 engine::math::operator*(engine::math::mat4, const engine::math::mat4&)’:
.../src/math/mat4.cpp:39:34: error: use of deleted function ‘engine::math::mat4::mat4(const engine::math::mat4&)’
             return left.mul(right);
                                  ^
In file included from .../src/math/mat4.cpp:5:0:
.../src/math/mat4.h:11:16: note: ‘engine::math::mat4::mat4(const engine::math::mat4&)’ is implicitly declared as deleted because ‘engine::math::mat4’ declares a move constructor or move assignment operator
         struct mat4 {
                ^

我该怎么办?

vec4声明复制构成器,因此没有为其类生成的隐式移动构建器。由于您的联合内部有一个vec4的数组,因此其移动组件被删除,因为vec4的s无法从中移动。此外,由于vec4具有用户提供的复制构建器,因此它被认为是非平凡的,因此联盟的复制构建器也被删除。由于工会是mat4的成员(并且工会具有删除的副本和移动构造人)mat4的副本和移动构建器也被删除。

删除功能仍然在过载分辨率中起作用,因此选择已删除的移动构建器,因为您是从临时性初始化返回值的。要解决此问题,请在vec4中声明一个默认的移动构建器:

struct vec4 {
    // ...
    vec4(vec4&&) = default;
    // ...
};

mat4中的复制构建器:

mat4(mat4 const&) {}

如果您需要复制任何成员,则必须手动进行Afaik。

0x499602d2的答案解释了您的错误,并回答了您问的特定问题。但是我认为,以两种可能的方式存储矩阵数据至少是一种奇怪的设计。并且您的实现与它不一致,因为在mat4& mat4::mul(const mat4 &other)(和其他方法)中,您仅使用联盟的elements部分。

IMHO您应该考虑:

  • 用简单的float elements[4 * 4];
  • 替换联盟
  • 添加一个构造函数,将4个vec4参数和存储值存储到elements数组
  • 添加一种从矩阵中提取向量的const方法

因为定义一个单个内部实现和随意的外部表示更为普遍。

它没有直接回答您的问题(@0x499602d2已经做到了),但是如果您遵循此建议,问题将消失,所以这个答案...