PDA

View Full Version : Cannot build a simple template



paie
5th August 2011, 22:39
I've been all over google trying to understand why I can't get this to work

I've tried all kinds of things I've seen out there, even including the source file (ugh!) but whenever I'm not getting compiler errors, I'm getting linker errors.

OK, maybe I'm just a rube.

Anyway the code below is throwing this compiler exception.

LNK2019 unresolved external symbol public: virtual __thiscall ControlGroup<class QRadioButton> .. yada ... yada ... yada

Here is the code that declares an instance of the template in a header file.

bits.h


#include "controlgroup.h"

class Ui_bits
{
public:
ControlGroup<QRadioButton> *pBitSize;

}


Here's the call that invokes the template and incurs the wrath of the linker.

bits.cpp


#include "bits.h"

void some_init_func()
{
Twidget tw;
ui->pBitSizes = new ControlGroup <QRadioButton>(&tw, ui->centralWidget);
}


Here is the header for the offending template class...

controlgroup.h

#ifndef CONTROLGROUP_H
#define CONTROLGROUP_H

#include <QtCore>
#include <QtGui>

typedef void (*pf)(int);

class Twidget
{
public:
QString name;
QSignalMapper mapper;
QList <pf> slotList;
int count;
};

template <typename T>
class ControlGroup : public QWidget
{
public:
explicit ControlGroup(Twidget *tw, QWidget *parent=0)
{
init (tw, parent );
}
ControlGroup(){};

void init( Twidget *tw, QWidget *parent);
~ControlGroup();
QList<T> widget;

private:
Twidget *m_tw;
QWidget *m_parent;

#include "controlgroup.cpp"
};

#endif // CONTROLGROUP_H


... and here's the source ...

controlgroup.cpp

#ifndef CONTROLGROUP_CPP
#define CONTROLGROUP_CPP

#include "controlgroup.h"

template <typename T>
void init( Twidget *tw, QWidget *parent )
{
for (int index = 0; index < tw->count; index++)
{
widget.append(new <T>(parent));
}
}

#endif


I'm sure it's something stupid, and that you guys frequently see ignorance like this.

It's probably a face-palmer, but I just can't figure it out.

stampede
5th August 2011, 23:19
class ...
private: ...

#include "controlgroup.cpp"
};

To be honest, I've never seen anything like that before :) Especially that the "controlgroup.cpp" includes the file in which it is included.
Why dont you just define the template class in one single header ? I think you can get away from your linker issues this way easily.

Santosh Reddy
5th August 2011, 23:37
As a standard C/C++ coding practice templates have to be declared and defined in same header file.

You can still have separate h and cpp files, in your case do the following things, it should work
1. remove #include "controlgroup.h" from controlgroup.cpp file.
2. all other files(.h, .cpp,...) in the project should only include "controlgroup.h", nothing should include "controlgroup.cpp" (except controlgroup.h, which you already have)

totem
5th August 2011, 23:41
also, in the init() method :


widget.append(new <T>(parent));

does not make sense. T is a type, so allocating new object is more like :


widget.append(new T(parent));


plus, in your ControlGroup constructor, init() must be called as a templated method, so it should be :


init<T>(tw, parent );

third, make sure you import <QRadioButton> header where you need to.

paie
6th August 2011, 01:17
As a standard C/C++ coding practice templates have to be declared and defined in same header file.

Ah! I was not aware of that. Ok, I have moved all the template stuff into the header file, both the template class declaraton and its definition. Standard practice has its reasons, and its benefits.


also, in the init() method :

widget.append(new <T>(parent));
does not make sense. T is a type, so allocating new object is more like :

widget.append(new T(parent));

OK, I fixed that. Thank you!


plus, in your ControlGroup constructor, init() must be called as a templated method, so it should be :

init<T>(tw, parent );

When I did that, the compiler gave me "C2275: 'T': "Illegal use of this type as an expression.


third, make sure you import <QRadioButton> header where you need to.
Yes, I have this included. In fact I have many other classes that declare instances of QRadioButton, and I have no problems. Besides, the syntax highlighter is excellent at giving you clues about whether you have your declarations and definitions going well.

When I removed the offending <T>, even with the whole template class declaration and definition in the same from the init call, the linker still throws "2019: Unresolved externals ...".

If I uncomment this line in the init routine, I can't even compile.


widgetList.append(new T(parent));

This causes the compiler to emit C2664: void QList<T>::append(const T&) : cannot convert parameter1 from 'QRadioButton * to const QRadioButton const &).

I don't know why I should get that. I declare new QRadioButtons without penalty elsewhere.

Here is the whole controlgroup.h file as it exists now.


#ifndef CONTROLGROUP_H
#define CONTROLGROUP_H

#include <QtCore>
#include <QtGui>
#include <QtGui/QWidget>
#include <QtGui/QRadioButton>

enum direction_t { go_left, go_right };
typedef void (*pf)(int);

class Twidget
{
public:
QString name;
QList <QLabel> labelList;
QList<QString> labelNames;
QSignalMapper mapper;
QList <pf> slotList;
int count; // Number of widgets
QRect geometry; // Size
QPoint start; // Where to start the layout
QPoint increment; // how to lay these out
direction_t direction; // go_left or go_right
};

template <typename T>
class ControlGroup : public QWidget
{
//Q_OBJECT
public:

explicit ControlGroup(Twidget *tw, QWidget *parent=0)
{
init(tw, parent);
}

ControlGroup();
~ControlGroup();

QList<T> widgetList;

void init( Twidget *tw, QWidget *parent);

private:
Twidget *m_tw;
QWidget *m_parent;

};

template <typename T>
void ControlGroup<T>::init( Twidget *tw, QWidget *parent )
{
for (int index = 0; index < tw->count; index++)
{
widgetList.append(new T(parent));
tw->labelList.append(new QLabel(parent));

}
}
#endif // CONTROLGROUP_H

paie
6th August 2011, 04:31
Well, I got it working.

The only thing I changed was I added empty curly brackets followed by a semicolon to the default constructor and the destructor.

I'm still very stumped why it wouldn't link and why the error messages were so obscure. I looked them up on google, but the information was sparse and laconic.

Thanks for all your help, though.