Tendo lido bastante sobre o propósito das uniões e trocadilhos de tipos (que basicamente não são permitidos e você deve confiar na otimização do compilador para eliminar chamadas memcpy), estou me perguntando se o seguinte uso de uma união é inseguro, ou se é um comportamento indefinido, ou se é, de fato, um uso perfeitamente compatível e seguro de uma união. A ideia é que os dados subjacentes sejam todos do mesmo tipo fundamental (int, double, etc.), mas eu só quero observar como eles são dispostos de maneiras diferentes ou nomeados de maneiras diferentes. Eu talvez chamaria isso de "trocadilho de contêiner" em vez de "trocadilho de tipos".
// main.cpp
// compile with `c++ main.cpp -std=c+23`
#include <iostream>
#include <array>
#include <format>
struct Mat2 {
union {
std::array<float, 4> data;
std::array<std::array<float, 2>, 2> rows;
struct { float x, y, z, w; };
};
};
int main() {
// sometimes you want to think about it in rows
Mat2 m{ .rows = {{ {0, 1},
{2, 3} }}};
for (auto &row : m.rows) {
for (auto &col : row) {
std::cout << col << " ";
}
std::cout << "\n";
}
// sometimes you want to think about it as a block of data
std::cout << "\n";
for (auto &d : m.data) {
std::cout << d << " ";
}
std::cout << "\n\n";
// sometimes you want to access elements based on sematic names
std::cout << std::format("{}, {}, {}, {}", m.x, m.y, m.z, m.w);
std::cout << std::endl;
}
As uniões em C++ não permitem trocadilhos de tipos (apenas em casos muito específicos que não se aplicam aqui). Não há garantia de que o layout de memória do array seja o esperado (veja O endereço de um std::array é garantidamente o mesmo que seus dados? ).
No entanto, você não precisa de uma união. Você pode fornecer diferentes acessores:
Geralmente, isso não deve afetar o layout dos dados mais do que o necessário quando tudo o que você deseja são visualizações diferentes dos mesmos dados.