Compile problem



  • Hello guys,

    Im getting this error when attempting to compile: U:\proj\dfw\mainwindow.cpp:-1: error: undefined reference to `void ui_sync_and_save::addUiItem<int>(QObject*, int&, uiItemMath, double)'

    mainWin .h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    #include <QMainWindow>
    #include "../usual/ui_sync_and_save.h"
    
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
    
    
        explicit MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
       ui_sync_and_save test;
       int val=0;
    private slots:
    
    private:
        Ui::MainWindow *ui;
    };
    
    #endif // MAINWINDOW_H
    
    
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    

    mainWin .cpp

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        test.addUiItem(ui->checkBox,val);//compile problem occurs here<<<<<
    
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    

    include .h

    #ifndef UI_SYNC_AND_SAVE_H
    #define UI_SYNC_AND_SAVE_H
    
    #include <QObject>
    #include "QSettings"
    
    using namespace std;
    
    enum uiOp{
        valToUi,
        valFromUi,
        fileFromUi,
        fileToUiAndPtr
    };
    
    enum uiItemMath{
       noCorrection,add,rem,multip,divide
    };
    
    class ui_sync_and_save : public QObject
    {
       // Q_OBJECT
    public:
    
        ui_sync_and_save();
    
    
    
        enum uiItems{
            spinBox,doubleSpinBox,checkBox,radioButton,dateTimeEdit
        };
    
        struct uiItem{
            QObject*ptr;
            void*valPtr;
            bool writeLock=0;
            uiItems type;
            uiItemMath mathOp;
            double mathVal;
        };
        vector<uiItem>uiItems;
    
        template <typename S>
        void addUiItem(QObject*uiItem,S&setVariable,uiItemMath correctionOp=noCorrection,double correctionVal=0);
        void syncUiVals(QObject *target=NULL, uiOp op=uiOp::valFromUi);
    
        QSettings uiSet;
        void saveUiValsToFile(QString path);
        void loadUiValsFromFile(QString path);
    
        bool setWriteLock(QObject*uiItem, bool lock);
    
        template <typename Val>
        QString n(Val num,char decimals=2){
           if(typeid(num)==typeid(double)){
               return QString::number(num,'f',decimals);
           }else{
               return QString::number(num);
           }
        }
    
    private:
        template <typename V>
        V valCorrection(V val,uiItem&itm,uiOp op=valFromUi);
    
    public slots:
        void syncSingleVal();
    
    signals:
        QString errorMsg(QString error){
            return error;
        }
    };
    
    #endif // UI_SYNC_AND_SAVE_H
    
    
    

    include .cpp

    #include "ui_sync_and_save.h"
    #include "QDoubleSpinBox"
    #include "QSpinBox"
    #include "QCheckBox"
    #include "QRadioButton"
    #include "QDateTimeEdit"
    
    ui_sync_and_save::ui_sync_and_save()
    {
    
    }
    
    template<typename S>//possibly template related mistake here<<<<<<<<
    void ui_sync_and_save::addUiItem(QObject *uiItem, S &setVar, uiItemMath mathOp, double mathVal)
    {
        ui_sync_and_save::uiItem item;
         item.ptr=uiItem;
         item.valPtr=&setVar;
         item.mathOp=mathOp;
         item.mathVal=mathVal;
    
             QDoubleSpinBox*dsBox=qobject_cast<QDoubleSpinBox*>(item.ptr);
             if (dsBox != NULL){
                 item.type=doubleSpinBox;
                 connect(dsBox, SIGNAL(valueChanged(double)), this, SLOT(syncSingleVal()));
                 uiItems.emplace_back(item);
                 return;
             }
    
             QSpinBox*sBox=qobject_cast<QSpinBox*>(item.ptr);
             if (sBox != NULL){
                 item.type=spinBox;
                 connect(sBox, SIGNAL(valueChanged(int)), this, SLOT(syncSingleVal()));
                 uiItems.emplace_back(item);
                 return;
             }
    
             QCheckBox*cBox=qobject_cast<QCheckBox*>(item.ptr);
             if (cBox != NULL){
                 item.type=checkBox;
                 connect(cBox, SIGNAL(stateChanged(int)), this, SLOT(syncSingleVal()));
                 uiItems.emplace_back(item);
                 return;
             }
             QRadioButton*rBut=qobject_cast<QRadioButton*>(item.ptr);
             if (rBut != NULL){
                 item.type=radioButton;
                 connect(rBut, SIGNAL(pressed()), this, SLOT(syncSingleVal()));
                 uiItems.emplace_back(item);
                 return;
             }
    
    
             QDateTimeEdit*dtEdit=qobject_cast<QDateTimeEdit*>(item.ptr);
             if (dtEdit != NULL){
                 item.type=dateTimeEdit;
                 connect(dtEdit, SIGNAL(dateTimeChanged(QDateTime)), this, SLOT(uuendaSet()));
                 uiItems.emplace_back(item);
                 return;
             }
    
           emit errorMsg("UiItemCastsFailed");
    
    }
    
    
    #ifdef QT_DEBUG
        int nullCounter=0;
    #endif
        void ui_sync_and_save::syncUiVals(QObject *target,uiOp op)
        {
    
        #ifdef QT_DEBUG
            if(op==uiOp::valFromUi && target==NULL){
                nullCounter++;
                if(nullCounter>1)
                    emit errorMsg("loopTroughUiItems NULL passed "+n(nullCounter)+" times.. Could use only once for initialization and set loading");
            }
        #endif
    
    
            bool found=0;
    
            for(auto &item:uiItems){
    
                if((target!=NULL && item.ptr!=target)||(item.writeLock&&op==uiOp::valFromUi)){
                    continue;
                }else{
                    found=1;
                }
    
                switch (item.type) {
    
                case spinBox:{
                    QSpinBox*sBox=qobject_cast<QSpinBox*>(item.ptr);
                    if (sBox != NULL){
                        int*p=(int*)item.valPtr;
                        switch (op){
                         case uiOp::valToUi:
                            sBox->setValue(valCorrection(*p,item,uiOp::valToUi));
                            continue;
                         case uiOp::valFromUi:
                            *p=valCorrection(sBox->value(),item);  ;
                            continue;
                         case uiOp::fileFromUi:
                             uiSet.setValue(sBox->objectName(), sBox->value());
                            continue;
                         case uiOp::fileToUiAndPtr:
                            sBox->setValue(uiSet.value(sBox->objectName()).toInt());
                            continue;
                        }
                    }}
                case doubleSpinBox:{
                    QDoubleSpinBox*dsBox=qobject_cast<QDoubleSpinBox*>(item.ptr);
                    if (dsBox != NULL){
                        double*p=(double*)item.valPtr;
                        switch (op){
                         case uiOp::valToUi:
                            dsBox->setValue(valCorrection(*p,item,uiOp::valToUi));
                            continue;
                         case uiOp::valFromUi:
                            *p=valCorrection(dsBox->value(),item);
                            continue;
                         case uiOp::fileFromUi:
                             uiSet.setValue(dsBox->objectName(), dsBox->value());
                            continue;
                         case uiOp::fileToUiAndPtr:
                            dsBox->setValue(uiSet.value(dsBox->objectName()).toDouble());
                            continue;
                        }
                    }}
                case checkBox:{
                    QCheckBox*cBox=qobject_cast<QCheckBox*>(item.ptr);
                    if (cBox != NULL){
                        bool*p=(bool*)item.valPtr;
                        switch (op){
                         case uiOp::valToUi:
                            cBox->setChecked(*p);
                            continue;
                         case uiOp::valFromUi:
                            *p=cBox->isChecked();
                            continue;
                         case uiOp::fileFromUi:
                             uiSet.setValue(cBox->objectName(), cBox->isChecked());
                            continue;
                         case uiOp::fileToUiAndPtr:
                            cBox->setChecked(uiSet.value(cBox->objectName()).toBool());
                            continue;
                        }
                    }}
    
                case radioButton:{
    
                    QRadioButton*rBut=qobject_cast<QRadioButton*>(item.ptr);
                    if (rBut != NULL){
                        bool*p=(bool*)item.valPtr;
                        switch (op){
                         case uiOp::valToUi:
                            rBut->setChecked(*p);
                            continue;
                         case uiOp::valFromUi:
                            *p=rBut->isChecked();
                            continue;
                         case uiOp::fileFromUi:
                             uiSet.setValue(rBut->objectName(), rBut->isChecked());
                            continue;
                         case uiOp::fileToUiAndPtr:
                            rBut->setChecked(uiSet.value(rBut->objectName()).toBool());
                            continue;
                        }
                    }
                }
                case dateTimeEdit:{
    
                    QDateTimeEdit*dtEdit=qobject_cast<QDateTimeEdit*>(item.ptr);
                    if (dtEdit != NULL){
                        QDateTime*p=(QDateTime*)item.valPtr;
                        switch (op){
                         case uiOp::valToUi:
                            dtEdit->setDateTime(*p);
                            continue;
                         case uiOp::valFromUi:
                            *p=dtEdit->dateTime();
                            continue;
                         case uiOp::fileFromUi:
                            uiSet.setValue(dtEdit->objectName(), dtEdit->dateTime());
                            continue;
                         case uiOp::fileToUiAndPtr:
                            dtEdit->setDateTime(uiSet.value(dtEdit->objectName()).toDateTime());
                            continue;
                        }
                    }}
                default:{
                    emit errorMsg("ui CaseNotDefined or type and passed ptr mismatch, nam: "+item.ptr->objectName());
                    continue;
                }
                }
    
                if(!found)
                   emit errorMsg("ui ptr not found , nam:"+item.ptr->objectName());
    
    
            }
    
             if(op==uiOp::fileToUiAndPtr){
                 syncUiVals(NULL,uiOp::valFromUi);
                 #ifdef QT_DEBUG
                      nullCounter--;
                 #endif
             }
    
        }
    
        void ui_sync_and_save::syncSingleVal(){
             syncUiVals(sender());//should return ptr of signal caller widget
        }
    
        void ui_sync_and_save::saveUiValsToFile(QString path)
        {
            uiSet.setPath(QSettings::IniFormat,QSettings::UserScope, path);
            syncUiVals(NULL,uiOp::fileFromUi);
        }
    
        void ui_sync_and_save::loadUiValsFromFile(QString path)
        {
            uiSet.setPath(QSettings::IniFormat,QSettings::UserScope, path);
            syncUiVals(NULL,uiOp::fileToUiAndPtr);
        }
    
        bool ui_sync_and_save::setWriteLock(QObject *uiItem,bool lock)
        {
            for(auto &item:uiItems){
                if(item.ptr==uiItem){
                  item.writeLock=lock;
                  return 1;
                }
            }
            return 0;
        }
    
    
    
        template<typename V>
        V ui_sync_and_save::valCorrection(V val, uiItem &itm,uiOp op)
        {
                switch (itm.mathOp) {
                noCorrection:
                return val;
                add:
                if(op=valFromUi){
                    return val-itm.mathVal;
                }else{
                    return val+itm.mathVal;
                }
                rem:
                if(op=valFromUi){
                    return val+itm.mathVal;
                }else{
                    return val-itm.mathVal;
                }
                multip:
                if(op=valFromUi){
                    return val/itm.mathVal;
                }else{
                    return val*itm.mathVal;
                }
                div:
                if(op=valFromUi){
                    return val*itm.mathVal;
                }else{
                    return val/itm.mathVal;
                }
    
                }
    
        }
    
    
    

    All help is welcome.


  • Moderators

    Templates are instantiated at the call site, so their body needs to be available at that point. The error says it's not.
    To fix this and as a general rule of thumb - move your template implementation to the header file.



  • Wonderful , also had some problems with using signals improperly.


 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.