C ++テンプレートクラス/関数、ソースファイルとは別のヘッダーファイル

テンプレートを含むソースファイルをヘッダーファイルから分離する

重要なのは、テンプレートの明示的なインスタンス化にあります。

解決

ソースファイルを分離するテンプレート機能

  1. 通常の方法で書き込み.h.cppファイル行います、追加されたtemplate <typename T>ステートメントに注意してください。
  2. .cppファイル最後に显式实例化、次のようなテンプレートコードを追加ます
// 显式实例化,注意,`template`之后没有`<>`,若添加则会报错!
// 每种将被使用的类型,均需要进行显式实例化
template void A::show(int &&);
template void A::show(double &&);
template void A::show(bool &&);

テンプレートクラスの個別のソースファイル

  1. テンプレートクラス.h.cppファイルを別々template <typename T>記述し、追加されたステートメントに注意してください。
  2. .cppファイル最後に显式实例化、次のようなクラスのコードを追加します。
// 只需要class的显式实例化即可,不需要再写其成员函数的显式实例化代码
template class Base<QLabel>;
  1. このテンプレートクラスを使用する他のクラスの.hファイル最後に、外部テンプレートクラスを追加します显式实例化声明externキーワードをもう1つ追加)。
// 添加这行代码的目的,其实是为了消除编译警告。即便删掉它,也不会导致编译错误
extern template class Base<QLabel>;

以上は、テンプレート関数・クラスのソースファイルとヘッダーファイルを分離する方法の簡単な説明でしたが、記載漏れがあることは避けられません。それでも質問がある場合は、特定のケースを引き続き確認できます。


サンプルコード

テンプレート機能

  • 番目
#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);
}

直接コンパイルするだけです:

a: t.cpp main.cpp
	g++ $^ -o $@ -std=c++17

実行:

./a
​```output
i
d
b
​```end

テンプレートクラス

テンプレートクラス(基本クラス)

  • ヘッドファイル
#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;

};
  • ソースファイル
#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>;

テンプレートクラスの通常の派生クラス

  • ヘッドファイル
#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>;

  • ソースファイル
#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);
}


テンプレートから派生したクラスからコンパイラの警告を排除する方法

  1. テンプレートクラスbase classのcppファイル最後に、明示的なインスタンス化コードを追加します。
template class Base<QLabel>;
  1. テンプレートクラスbase classの.cppファイル先頭に、インクルードファイルを追加します。
#include <QLabel>
  1. テンプレートクラスの一般的な派生クラスの.hファイルの最後外部宣言コードを追加します。
extern template class Base<QLabel>;

おすすめ

転載: blog.csdn.net/gkzscs/article/details/108662174