4

私はこの関数宣言を持っています:

template<class T>
a::A& a::A::operator<<(T out) {
    std::cout << out;
    return (*this);
}

そしてこの関数の定義:

namespace a {
    ...
    class A {
        ...
        template<class T> A& operator<<(T);

そして私はそれを次のように呼びます:

a::A b;
b << 1;

これはMakefileです:

app: main.o A.o
    g++ main.o A.o -o app

main.o: main.cpp
    g++ -c main.cpp

A.o: A.cpp
    g++ -c A.cpp

そしてそれは私に与えます:

未定義のシンボル:a :: A&a :: A :: operator << <int>(int)

何故ですか?

4

2 に答える 2

6

Tによって表される型(つまりint、あなたの場合)が実際にわかると、関数テンプレートはコンパイル時に実際の関数に変換されます。ただし、これはmain.cppコンパイル前には当てはまりません。コンパイル時にA.cpp、テンプレート関数は実際の関数にインスタンス化されないため、生成されるオブジェクトファイルには関数のバイナリバージョンが含まれていません。

これを解決するには2つの方法があります。

  1. 関数定義をヘッダーファイルにインクルードします。つまり、

    template<class T>
    a::A& a::A::operator<<(T out) {
        std::cout << out;
        return (*this);
    }
    

    ヘッダーファイルの一部であり、.cppファイルから関数定義を削除します。

    この効果は、このヘッダーを含むすべてのファイルが、テンプレートの任意のインスタンス化、つまり、任意の値に対して使用できるようになる ことです.cppT

  2. または、明示的なテンプレートインスタンス化ステートメントをA.cpp:に含めます。

    template a::A& a::A::operator<<(int out);
    

    これにより、コンパイラA.cppはコンパイル時に実際にテンプレートをインスタンス化し、コンパイルされた関数をオブジェクトファイルに含めます。main.oしたがって、リンカはリンク時およびリンク時にそれを見つけることができA.o、すべて問題ありません。int欠点は、明示的なインスタンス化を指定した特定のタイプ(この場合はのみ)に対してのみ機能することです。

于 2012-10-31T02:43:51.367 に答える
-1

定義を次のように変更してみてください。

template<class T>
a::A& a::A::operator<< <T> (T out) {
    std::cout << out;
    return (*this);
}

(ヘッダーファイルにあることを確認してください)

于 2012-10-31T02:49:21.010 に答える