класс с объединенным использованием удаленной функции в конструкторе

Я пытаюсь сделать класс матрицы 4 * 4, он построен из массива из 16 чисел с плавающей запятой, но я также хочу представить его как массив из 4 vec4 (для каждого столбца).
Проблема в том, что он не компилируется и выдает ошибку везде, где я вызываю конструктор 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];
^

Я предполагаю, что большая часть кода не имеет значения, поэтому не стоит читать все это.
Просто для сравнения, если я удалю ссылку vec4 columns[4]; от союза в mat4.h, тогда все фантастически.

Я ломал голову над этим в течение последнего часа, поэтому мне действительно нужна помощь.

Благодарю.

РЕДАКТИРОВАТЬ:

После попытки того, что @ 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 {
^

Что я могу сделать, чтобы это исправить?

0

Решение

vec4 объявляет конструктор копирования, поэтому не существует неявного конструктора перемещения, сгенерированного для его класса. Так как у вас есть массив vec4 внутри вашего союза его Move-конструктор удаляется, так как vec4не может быть перенесен из. Более того, так как vec4 имеет предоставленный пользователем конструктор копирования, он считается нетривиальным и, таким образом, также удаляется конструктор копирования объединения. Поскольку профсоюз является членом mat4 (а объединение имеет удаленную копию и конструктор перемещения) mat4Копия и Move-конструктор тоже удалены.

Удаленные функции по-прежнему играют роль в разрешении перегрузки, поэтому выбирается удаленный конструктор перемещения, поскольку вы инициализируете возвращаемое значение из временного значения. Чтобы это исправить, объявите движущийся конструктор по умолчанию внутри vec4:

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

и конструктор копирования в mat4:

mat4(mat4 const&) {}

Если у вас есть участники, которые нужно скопировать, вы должны сделать это вручную AFAIK.

2

Другие решения

Ответ 0x499602D2 объясняет вашу ошибку и отвечает на конкретный вопрос, который вы задали. Но я думаю, что по крайней мере странный дизайн хранить матричные данные двумя возможными способами. И ваша реализация не согласуется с этим, так как в mat4& mat4::mul(const mat4 &other) (и другие методы) вы используете только elements часть союза.

ИМХО, вы должны учитывать:

  • заменить союз простым float elements[4 * 4];
  • добавить конструктор, принимая 4 vec4 параметры и сохранение значений в elements массив
  • добавить метод const для извлечения векторов из матрицы

Потому что гораздо чаще определять одну единственную внутреннюю реализацию и столько внешний представления, как вы хотите.

Он не дает прямого ответа на ваш вопрос (@ 0x499602D2 уже сделал), но если вы последуете этому совету, проблема исчезнет, ​​поэтому этот ответ …

0

По вопросам рекламы [email protected]