Separe los archivos de origen que contienen plantillas de los archivos de encabezado
La clave está en la instanciación explícita de la plantilla.
solución
Función de plantilla para separar archivos fuente
- Escriba
.h
y.cpp
archive de la manera habitual , pero preste atención a latemplate <typename T>
declaración agregada ; - Al
.cpp
final del archivo, agregue el显式实例化
código de plantilla , como:
// 显式实例化,注意,`template`之后没有`<>`,若添加则会报错!
// 每种将被使用的类型,均需要进行显式实例化
template void A::show(int &&);
template void A::show(double &&);
template void A::show(bool &&);
Archivo fuente separado de clase de plantilla
- Escriba la clase de plantilla
.h
y el.cpp
archivo por separado , preste atención a latemplate <typename T>
declaración agregada ; - Al
.cpp
final del archivo, agregue el显式实例化
código de la clase , como:
// 只需要class的显式实例化即可,不需要再写其成员函数的显式实例化代码
template class Base<QLabel>;
- Al
.h
final del archivo de otras clases que usan esta clase de plantilla , agregue la clase de plantilla externa显式实例化声明
(solo unaextern
palabra clave más ):
// 添加这行代码的目的,其实是为了消除编译警告。即便删掉它,也不会导致编译错误
extern template class Base<QLabel>;
Lo anterior es una breve descripción del método para separar el archivo fuente y el archivo de encabezado de la función / clase de plantilla Es inevitable que haya omisiones. Si aún tiene preguntas, puede continuar viendo casos específicos.
Código de muestra
Función de plantilla
- th
#ifndef _T_H
#define _T_H
class A
{
public:
template <typename T>
void show(T &&t);
};
#endif // _T_H
- t.cpp
#include "t.h"
#include <iostream>
using namespace std;
template <typename T>
void A::show(T &&t)
{
string info = typeid(t).name();
cout << info << endl;
}
// 显式实例化,注意,`template`之后没有`<>`,若添加则会报错!
template void A::show(int &&);
template void A::show(double &&);
template void A::show(bool &&);
- main.cpp
#include <iostream>
#include "t.h"
using namespace std;
int main()
{
A a;
a.show(1);
a.show(3.4);
a.show(true);
}
Simplemente compile directamente:
a: t.cpp main.cpp
g++ $^ -o $@ -std=c++17
correr:
./a
```output
i
d
b
```end
Clase de plantilla
Clase de plantilla (clase base)
- archivo de cabeza
#include <QObject>
class QLabel;
template <typename T>
class Base : public QObject
{
public:
Base(QObject *parent = nullptr);
virtual ~Base() override;
void add(T *t);
void remove(T *t);
void remove(int idx);
T *find(int idx) const;
protected:
QList<T *> _listItems;
};
- Archivo fuente
#include "base.h"
#include <QLabel>
template <typename T>
Base<T>::Base(QObject *parent)
: QObject(parent)
{
// Do nothing
}
template <typename T>
Base<T>::~Base()
{
qDeleteAll(_listItems);
_listItems.clear();
}
template <typename T>
void Base<T>::add(T *t)
{
_listItems.append(t);
}
template <typename T>
void Base<T>::remove(T *t)
{
_listItems.removeAll(t);
}
template <typename T>
void Base<T>::remove(int idx)
{
_listItems.removeAt(idx);
}
template <typename T>
T *Base<T>::find(int idx) const
{
return _listItems.at(idx);
}
/************************************ Explicit Instantiate *****************************/
template class Base<QLabel>;
Clase derivada ordinaria de clase de plantilla
- archivo de cabeza
#include "base.h"
class QLabel;
class Son : public Base<QLabel>
{
public:
Son(QObject *parent = nullptr);
virtual ~Son() override;
protected:
void init();
};
/********************************** Explicit Instantiate *****************************/
extern template class Base<QLabel>;
- Archivo fuente
#include "son.h"
#include <QLabel>
Son::Son(QObject *parent)
: Base<QLabel>(parent)
{
init();
}
Son::~Son()
{
// Do nothing
}
void Son::init()
{
add(new QLabel());
remove(new QLabel);
remove(123);
find(321);
}
Formas de eliminar las advertencias del compilador de clases derivadas de plantillas
- Al
cpp
final del archivo de la clase base de la clase de plantilla , agregue el código de instanciación explícito:
template class Base<QLabel>;
- Al
.cpp
comienzo del archivo de la clase base de la clase de plantilla , agregue un archivo de inclusión:
#include <QLabel>
.h
Agregue el código de declaración externa al final del archivo de la clase de plantilla clase derivada general :
extern template class Base<QLabel>;