Search code examples
c++c++17temporary-objects

Generating a warning when a member function is invoked on a temporary object


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?


Solution

  • 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.