1

プロジェクトファイルは次のとおりです。

source
  parser
    parser.cpp
    parser.hpp
  brain
    brain.cpp
    brain.hpp

最初に次の 2 つのコマンド ( pwd source/brain/)を実行しました。

g++ -c brain.cpp -o brain.o
ar rvs brain.a brain.o

brain.aと の両方をにコピーしbrain.hppましたsource/parser/。次に、このコマンドを実行しました( pwd source/parser):

g++ parser.cpp brain.a -o parser

そして、私はこのエラーを受け取りました:

/tmp/cceGRLZn.o: In function `main':
parser.cpp:(.text+0x1cc): undefined reference to `std::brain<long long>::brain()'
parser.cpp:(.text+0x205): undefined reference to `std::brain<long long>::init(int)'
parser.cpp:(.text+0x26b): undefined reference to `std::brain<long long>::work()'
parser.cpp:(.text+0x2a4): undefined reference to `std::brain<long long>::clear()'
parser.cpp:(.text+0x2ec): undefined reference to `std::brain<long long>::~brain()'
parser.cpp:(.text+0x322): undefined reference to `std::brain<long long>::~brain()'
/tmp/cceGRLZn.o: In function `int parser_extract_args<long long>(std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, int, short&, std::brain<long long>&)':
parser.cpp:(.text._Z19parser_extract_argsIxEiRSsiRsRSt5brainIT_E[int parser_extract_args<long long>(std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, int, short&, std::brain<long long>&)]+0x17b): undefined reference to `std::brain<long long>::push_back(long long)'
parser.cpp:(.text._Z19parser_extract_argsIxEiRSsiRsRSt5brainIT_E[int parser_extract_args<long long>(std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, int, short&, std::brain<long long>&)]+0x37a): undefined reference to `std::brain<long long>::push_back(long long)'
collect2: ld returned 1 exit status

ソース ファイル:

brain.cpp [http://ideone.com/GNUxmH][1]
brain.hpp [http://ideone.com/M2IFAI][2]
parser.cpp [http://ideone.com/fJRzhD][3]
parser.hpp [http://ideone.com/mj6dST][4]

私は何をすべきか?

4

3 に答える 3

3

まず、名前空間にエンティティを追加しないでくださいstd。これにより、プログラムにUndefined Behaviorが与えられます。

brainあなたのメッセージから、std名前空間にという名前のクラスを追加したようです。名前空間から削除brainして、stdあなたの名前空間に入れます。std名前空間に追加できる唯一のものは、名前空間に属するテンプレートの特殊std化です。

次に、プログラム全体で使用しているクラス テンプレートの明示的なインスタンス化を提供しない限り、クラス テンプレートメンバー関数の定義を、それらの宣言を含む同じヘッダー ファイルに配置して、それらがインスタンス化から確実に見えるようにする必要があります。点。

それらを別の.cppファイルに格下げすると、コンパイラは、定義を含む翻訳単位以外の翻訳単位から呼び出しているメンバー関数のコードを生成できなくなります。StackOverflow に関するこの Q&Aも役立つ場合があります。

于 2013-04-06T12:34:50.550 に答える
1

クラス テンプレートのメンバー関数をファイルに実装したに違いありませbrain.cpp。テンプレートのインスタンス化を確認したときにコンパイラが適切なコードを生成できるように、ヘッダー ファイルにテンプレート定義を指定する必要があります。の内容をbrain.cppまで移動しbrain.hます。

例として、次の 3 つのファイルについて考えてみましょう。

  • test.h

    template <typename T>
    struct test
    {
      void foo(T);
    };
    
  • test.cpp

    #include "test.h"
    
    template <typename T>
    void test<T>::foo(T x)
    {
      // do something with x
    }
    
  • main.cpp

    #include "test.h"
    
    int main()
    {
      test<int> t;
      t.foo(5);
    }
    

それぞれ.cppが個別にコンパイルされてから、一緒にリンクされます。あなたがコンパイラであり、コンパイルしようとしていると想像してくださいmain.cpp。コードがastestでインスタンス化されたテンプレートを使用しようとしていることがわかります。したがって、適切な のコードを生成する必要がありますが、そのためには関数の定義を確認する必要があります。残念ながら、あなたはそれを見ていないので、このプログラムをコンパイルすることはできません。Tinttest<int>::foo

代わりに、 の定義をfooヘッダー ファイルに移動して、次の 2 つのファイル プログラムを作成する必要があります。

  • test.h

    template <typename T>
    struct test
    {
      void foo(T);
    };
    
    // Alternatively, you can define this up in the class definition
    void test<T>::foo(T x)
    {
      // do something with x
    }
    
  • main.cpp

    #include "test.h"
    
    int main()
    {
      test<int> t;
      t.foo(5);
    }
    

std名前空間に独自の宣言を追加しないでください。

std特に指定がない限り、名前空間 std または名前空間内の名前空間に宣言または定義を追加する場合、C++ プログラムの動作は未定義です。

于 2013-04-06T12:33:50.783 に答える
1

必要なタイプのブレイン テンプレート クラスのインスタンスを宣言する必要があるため、brain.cpp のファイルの最後に次のように記述します。

template class brain <long long> ;

Brain.cpp をコンパイルすると、そこにテンプレート指定子がない限り、型宣言なしでテンプレート クラスをインスタンス化できないため、リンク可能なコードは作成されません。とはいえ、テンプレート化されたクラスを使用する場合は、それらを純粋なヘッダー ファイルとして保持することをお勧めします

于 2013-04-06T12:36:02.347 に答える