0

私は次の簡単なテンプレートコードを持っています:

#ifndef CLUSTER_H
#define CLUSTER_H

#include <iostream>
#include <vector>

template <typename T, size_t K>
class Cluster
{
public:
    void Print() const;     
private:
    std::vector<T> objects;
};
template <typename T, size_t K>
void Cluster<T,K>::Print() const
{
    for (int i=0; i<objects.size(); i++)
    {
        T curr=objects[i];
        std::cout << curr << " ";
    }
    std::cout << std::endl;
}

#endif

そして、何らかの理由で次のエラーが発生します:「' Cluster<int, 5u>::Print() const'への未定義の参照。これの原因は何でしょうか?ありがとうございます!

4

1 に答える 1

2

ここで、CPP ファイルでテンプレート関数を定義したとしましょう。これは、別の翻訳単位で終了することを意味します。簡単な例を次に示します。

ヘッダー、example.h

#ifndef EXAMPLE_H
#define EXAMPLE_H

template<int TValue>
class example
{
public:
    int get_tvalue();
};

#endif

ソース ファイル、example.cpp

#include "example.h"

template<int TValue>
int example<TValue>::get_tvalue()
{
    return TValue;
}

もう 1 つのソース ファイル、main.cpp

#include "example.h"

int main()
{
    example<5> instance;
    instance.get_tvalue();
    return 0;
}

GCC を使用してこれらをまとめてコンパイルすると、undefined reference to 'example<5>::get_tvalue()'. これは、テンプレート クラスがインスタンス化される方法によるものです。テンプレートクラスの定義はまさに... テンプレートであり、実際のクラスではありません。実際のクラス定義は、そのクラスのパラメーター化された (具体的には、完全に特殊化された) 定義が発生したときに作成されます。この場合はexample<5>. その完全に特殊化されたクラス定義は main.cpp にのみ存在します... example.cpp 内にそのようなクラスはありません! Example.cpp にはテンプレートのみが含まれ、特殊化は含まれていません。これは、関数が main.cpp でget_tvalue定義されていないことを意味するため、エラーが発生します。example<5>

これは、2 つの方法のいずれかで修正できます。最初の方法は、テンプレート クラス全体を常にヘッダー ファイルで定義することです。これは、たとえば STL コンテナーで行われる方法です。別の方法は、example.cpp でパラメータ化されたクラスの作成を強制することです...追加することでこれを行うことができます

template class example<5>;

example.cpp の最後まで。example.cpp には実際のクラス定義があるため、コンパイル ステップの最後に変換ユニット main.o と example.o がリンクされると、 andexample<5>の実際の関数定義も得られます。example<5>::get_tvalue

明らかに、ほとんどの場合、これは不適切なアプローチですが、テンプレート パラメーターが小さな範囲の値しかとらない状況では機能します。ただし、クラス全体をヘッダー ファイルに配置するのが、おそらく最も簡単で、最も安全で、最も柔軟です。

于 2012-06-19T13:26:33.720 に答える