Given a matrix template class mat<M,N,T>
the following member function allows me to efficiently transpose a row vector or a column vector, since they have the same/corresponding memory footprint:
template<int M, int N=M, typename T = double>
struct mat {
// ...
template<int Md = M, int Nd = N, typename = std::enable_if_t<Md == 1 || Nd == 1>>
const mat<N, M, T>& transposedView() const {
static_assert(M == 1 || N == 1, "transposedView() supports only vectors, not general matrices.");
return *reinterpret_cast<const mat<N, M, T>*>(this);
}
}
I've been using this function for years and out of habit started calling it on temporary expressions (/*vector-valued expression*/).transposedView()
, forgetting that it would then return a reference to a temporary, and result in undefined behavior by which GCC just bit me.
Is there a simple way for me to add something that would generate some kind of warning when I invoke it on a temporary?
Or is it actually supposed to be safe to call it on a temporary as long as I don't store the reference?
Member function can be qualified for lvalue or rvalue objects. Using that, you can create an overload set like
template<int M, int N=M, typename T = double>
struct mat {
// ...
template<int Md = M, int Nd = N, typename = std::enable_if_t<Md == 1 || Nd == 1>>
const mat<N, M, T>& transposedView() & const {
static_assert(M == 1 || N == 1, "transposedView() supports only vectors, not general matrices.");
return *reinterpret_cast<const mat<N, M, T>*>(this);
}
template<int Md = M, int Nd = N, typename = std::enable_if_t<Md == 1 || Nd == 1>>
const mat<N, M, T>& transposedView() && const = delete;
}
and now if you try to call the function with an rvalue object, you will get a compiler error.