Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Undefined reference error



  • I'm still new to both Qt and c++ so I apologize if I am missing something simple. I have found other threads relating to this topic and I have tried those solutions with no success.

    I'm creating a class that inherits qobject that will row reduce a matrix. I've tested the code that does this and it works when inside main.cpp. I have trouble getting it to work when I put the code into its own header and source files.

    The error I get is:
    main.cpp:22: error: undefined reference to `matclass::to_reduced_echelon_form(Eigen::Matrix<double, -1, -1, 0, -1, -1>&)'

    From what I've found this is likely a linking error with .o files but I'm not entirely sure how to fix that or if that is even an issue when using QtCreator. Thanks in advance for any advice!

    matclass.h

    #ifndef MATCLASS_H
    #define MATCLASS_H
    
    #include <QObject>
    #include <QObject>
    #include <Eigen>
    #include <algorithm>
    #include <cstddef>
    #include <cassert>
    
    class matclass : public QObject
    {
        Q_OBJECT
    public:
        explicit matclass(QObject *parent = nullptr);
    
        struct matrix_traits
        {
            typedef typename Eigen::MatrixXd::value_type value_type;
    
            static int min_row(Eigen::MatrixXd const& A);
            static int max_row(Eigen::MatrixXd const& A);
            static int min_column(Eigen::MatrixXd const& A);
            static int max_column(Eigen::MatrixXd const& A);
            static value_type& element(Eigen::MatrixXd& A, int i, int k);
            static value_type element(Eigen::MatrixXd const& A, int i, int k);
        };
        void swap_rows(Eigen::MatrixXd& A, int i, int k);
        void divide_row(Eigen::MatrixXd& A, int i, typename matrix_traits::value_type v);
        void add_multiple_row(Eigen::MatrixXd& A, int i, int k, typename matrix_traits::value_type v);
        void to_reduced_echelon_form(Eigen::MatrixXd& A);
    
    signals:
    
    };
    
    #endif // MATCLASS_H
    

    matclass.cpp

    #include "matclass.h"
    
    matclass::matclass(QObject *parent) : QObject(parent)
    {
    
    }
    
    struct matrix_traits
    {
        typedef typename Eigen::MatrixXd::value_type value_type;
    
        static int min_row(Eigen::MatrixXd const& A)
        {
            return A.rows() - A.rows();
        }
        static int max_row(Eigen::MatrixXd const& A)
        {
            return A.rows() - 1;
        }
        static int min_column(Eigen::MatrixXd const& A)
        {
            return A.cols() - A.cols();
        }
        static int max_column(Eigen::MatrixXd const& A)
        {
            return A.cols() - 1;
        }
        static value_type& element(Eigen::MatrixXd& A, int i, int k)
        {
            return A(i, k);
        }
        static value_type element(Eigen::MatrixXd const& A, int i, int k)
        {
            return A(i, k);
        }
    };
    
    void swap_rows(Eigen::MatrixXd& A, int i, int k)
    {
        matrix_traits mt;
    
        assert(mt.min_row(A) <= i);
        assert(i <= mt.max_row(A));
    
        assert(mt.min_row(A) <= k);
        assert(k <= mt.max_row(A));
    
        for(int col = mt.min_column(A); col <= mt.max_column(A); ++col)
        {
            std::swap(mt.element(A, i, col), mt.element(A, k, col));
        }
    }
    
    void divide_row(Eigen::MatrixXd& A, int i, typename matrix_traits::value_type v)
    {
        matrix_traits mt;
    
        assert(mt.min_row(A) <= i);
        assert(i <= mt.max_row(A));
    
        assert(v != 0);
    
        for(int col = mt.min_column(A); col <= mt.max_column(A); ++col)
        {
            mt.element(A, i, col) /= v;
        }
    }
    
    void add_multiple_row(Eigen::MatrixXd& A, int i, int k, typename matrix_traits::value_type v)
    {
        matrix_traits mt;
    
        assert(mt.min_row(A) <= i);
        assert(i <= mt.max_row(A));
    
        assert(mt.min_column(A) <= k);
        assert(k <= mt.max_row(A));
    
        for(int col = mt.min_column(A); col <= mt.max_column(A); ++col)
        {
            mt.element(A, i, col) += v * mt.element(A, k, col);
        }
    }
    
    void to_reduced_echelon_form(Eigen::MatrixXd& A)
    {
        matrix_traits mt;
    
        int lead = mt.min_row(A);
    
        for(int row = mt.min_row(A); row <= mt.max_row(A); ++row)
        {
            if(lead > mt.max_column(A))
            {
                return;
            }
            int i = row;
            while (mt.element(A, i, lead) == 0)
            {
                ++i;
                if(i > mt.max_row(A))
                {
                    i = row;
                    ++lead;
                    if(lead > mt.max_column(A))
                    {
                        return;
                    }
                }
            }
            swap_rows(A, i, row);
            divide_row(A, row, mt.element(A, row, lead));
            for(i = mt.min_row(A); i <= mt.max_row(A); ++i)
            {
                if(i != row)
                {
                    add_multiple_row(A, i, row, -mt.element(A, i, lead));
                }
            }
        }
    }
    

    mian.cpp

    #include <QCoreApplication>
    #include <QDebug>
    
    #include "matclass.h"
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    /*
        Eigen::Matrix<double, 2, 2> M;
        M(0, 0) = 1;
        M(0, 1) = 2;
        M(1, 0) = 3;
        M(1, 1) = 4;
    */
        Eigen::MatrixXd Mat;
        Mat.resize(2, 2);
        Mat << 1, 2, 3, 4;
    
        matclass Matrix;
    
        Matrix.to_reduced_echelon_form(Mat);
    
        for(int i = 0; i < 2; i++)
        {
            for(int j = 0; j < 2; j++)
            {
                qDebug() << Mat(i, j) << " ";
            }
            qDebug() << "\n";
        }
    
        return a.exec();
    }
    

    .pro file

    QT -= gui
    
    INCLUDEPATH += C:\sdks\eigen3.3.8\eigen-3.3.8\Eigen
    
    CONFIG += c++11 console
    CONFIG -= app_bundle
    
    # You can make your code fail to compile if it uses deprecated APIs.
    # In order to do so, uncomment the following line.
    #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
    
    SOURCES += \
            main.cpp \
            matclass.cpp
    
    # Default rules for deployment.
    qnx: target.path = /tmp/$${TARGET}/bin
    else: unix:!android: target.path = /opt/$${TARGET}/bin
    !isEmpty(target.path): INSTALLS += target
    
    HEADERS += \
        matclass.h
    

  • Lifetime Qt Champion

    @sheetkey said in Undefined reference error:

    to_reduced_echelon_form

    I don't see an implemented function in the class matclass, only a free function.



  • @sheetkey
    Not only as per @Christian-Ehrlicher has observed, but it seems all your methods in the class (swap_rows() onward) are not implemented in the class. Your error on to_reduced_echelon_form() is only because that happens to be one you call.



  • @Christian-Ehrlicher @JonB Thank you very much! I've managed to sort it out now.


Log in to reply