I have an array wrapper that I use as a matrix/vector class, and a struct of two floats to represent points.
I don't want to re-define all arithmetic operators again for points, when I already have them available for vectors, so I want to add implicit conversions between them. I use reinterpret_cast
, as shown in the snippet below.
template <class T, size_t N>
struct Array {
T data[N];
constexpr T &operator[](size_t index) { return data[index]; }
constexpr const T &operator[](size_t index) const { return data[index]; }
};
template <class T, size_t R, size_t C>
using TMatrix = Array<Array<T, C>, R>;
template <class T, size_t R>
using TColVector = TMatrix<T, R, 1>;
struct Point {
float x;
float y;
constexpr Point(float x, float y) : x{x}, y{y} {}
constexpr Point(const TColVector<float, 2> &vec) : x{vec[0]}, y{vec[1]} {}
TColVector<float, 2> &vec() {
static_assert(sizeof(*this) == sizeof(TColVector<float, 2>));
return *reinterpret_cast<TColVector<float, 2> *>(this);
}
operator TColVector<float, 2> &() { return vec(); }
};
When using the implicit conversion from Point
to TColVector<float, 2>
, I get incorrect results. Even stranger: the results are correct as long as I print the intermediate results, but incorrect when I comment out the print statements. And it seems to be always correct on gcc 7.3.0 for x86, and sometimes incorrect on gcc 8.3.0 for ARMv7.
This is the function that gave a correct result with the print statements, and an incorrect result when I commented out the print statements:
static float distanceSquared(Point a, Point b) {
using namespace std;
// cout << "a = " << a << ", b = " << b << endl;
auto diff = a.vec() - b.vec(); // Array<T, N> operator-(const Array<T, N> &lhs, const Array<T, N> &rhs)
// cout << "diff = " << Point(diff) << endl;
auto result = normsq(diff); // auto normsq(const TColVector<T, C> &colvector) -> decltype(colvector[0] * colvector[0])
// cout << "normsq(diff) = " << result << endl;
return result;
}
Am I doing something wrong here?
The solution seems to be this (even though it doesn't work as an lvalue):
TColVector<float, 2> vec() const { return {x, y}; }
I tried to isolate the problem from the rest of my project, but I haven't been able to reproduce it in isolation, so I would like to know if I have to keep on looking for other problems, even though it seems alright for now.
Here's the entire code on GitHub (it doesn't seem to demonstrate the problem in isolation): https://github.com/tttapa/random/blob/master/SO-reinterpret_cast.cpp