2016-03-30 5 views
1

単純なテンプレートtrivial_template.hppのヘッダーファイル。C++テンプレートを使用したこの2つのケースで、なぜ矛盾しますか?

// Import packages from the C++ STL 
#include <string> 
#include <cstring> 
#include <stdio.h> 
#include <utility> 
#include <limits.h>   // For std::LONG_MIN 

#ifndef __TRIVIAL_TEMPLATE_H 
#define __TRIVIAL_TEMPLATE_H 
using namespace std; 

template <typename T> 
class trivial_template { 
    public: 
     trivial_template(); 
     ~trivial_template(); 
     static bool is_non_negative(T a_num); 
     T square_given_number(T a_num); 
}; 
#endif 

単純なテンプレートtrivial_template.cppの実装ファイル。

#include "./trivial_template.hpp" 

template <typename T> 
trivial_template<T>::trivial_template() { 
} 

template <typename T> 
trivial_template<T>::~trivial_template() { 
} 

template<typename T> 
bool trivial_template<T>::is_non_negative(T a_num) { 
    return (0 <= a_num); 
} 

template<typename T> 
T trivial_template<T>::square_given_number(T a_num) { 
    return (a_num*a_num); 
} 

これを使用するC++メインファイル。

#include <iostream> 
#include <iomanip> 
#include <string> 
#include <cstring> 
#include <math.h> 
#include <climits> 
#include <cfloat> 
#include <ctype.h> 
#include <stdio.h> 
#include <stdlib.h> 

#include "../../elements/trivial_template.hpp" 

using namespace std; 

int main(int argc, char *argv[]) { 
    cout << " ###" << trivial_template<int>::is_non_negative(493) << "===" << endl; 
    trivial_template<int> *a_ptr; 
    cout << " ###" << a_ptr->square_given_number(5) << "===" << endl; 
    // 0.25^2 = 0.0625 
    trivial_template<long double> *b_ptr; 
    cout << " ###" << b_ptr->square_given_number(-0.25) << "===" << endl; 
    // 16.25^2 = 164.0625 
    cout << " ###" << b_ptr->square_given_number(-16.25) << "===" << endl; 
    return 0; 
} 

私のコマンドをコンパイルすると、リンク、およびそれを実行するには、次のとおりです。

g++ -std=c++0x -c ../src/elements/trivial_template.cpp 
g++ -std=c++0x -c ../src/test/temp/test_templates.cpp 
g++ -std=c++0x -o ./test-boilerplate-code *.o 

リンク時に、次のエラーメッセージが生成されます

Undefined symbols for architecture x86_64: 
    "trivial_template<long double>::square_given_number(long double)", referenced from: 
     _main in test_templates.o 
    "trivial_template<int>::is_non_negative(int)", referenced from: 
     _main in test_templates.o 
    "trivial_template<int>::square_given_number(int)", referenced from: 
     _main in test_templates.o 
ld: symbol(s) not found for architecture x86_64 
clang: error: linker command failed with exit code 1 (use -v to see invocation) 
make: *** [template] Error 1 

私が使用して、この単純な例を試したときC++ソースファイルの場所の異なるパス、それは動作します。その出力は次のとおりです。

###1=== 
    ###25=== 
    ###0.0625=== 
    ###264.062=== 
real   0.22 
user   0.00 
sys   0.00 

なぜこの不一致がありますか?何が起こっている?

さらに、リンクエラーを修正するのを手伝ってもらえますか?

大変ありがとうございました!

+0

親愛なるギュンター、 あなたは矛盾がある理由を教えて親切にしていただけますか?私は何を間違えたのですか? 私にリンクした質問は参考になりますが、矛盾はありません。 ありがとうございます。 – Giovanni

+1

あなたのインクルードの上にあなたのインクルードガードを置くことをお勧めします。そうすれば、インクルードは同じファイルに対して2回解析されません。 – sdsmith

+1

http://stackoverflow.com/q/495021/179910いくつかのコンパイラでは、いくつかの状況下ではソースファイル内のテンプレートを扱うことができますが、使用している* exact *コンパイラが分からなければ、テンプレート全体をヘッダに入れるのが最も効果的です。 –

答えて

2

ヘッダーファイルにメソッドの実装を入れ、そのファイルをインクルードする必要があります。要するに、宣言と同様に、各翻訳単位でテンプレートを表示する必要があります。また、複数のインクルードを防ぐために、各ヘッダーファイルにインクルードガードを使用する必要があります。

/*template_declarations.hpp*/ 
    #ifndef TEMPLATE_DECLARATIONS_HPP 
    #define TEMPLATE_DECLARATIONS_HPP 

    // put your declarations here 

    #endif //TEMPLATE_DECLARATIONS_HPP 



    /*template_implementation.hpp*/ 
    #ifndef TEMPLATE_IMPLEMENTATION_HPP 
    #define TEMPLATE_IMPLEMENTATION_HPP 

    #include "template_declarations.hpp" 

    // put your implementation here 

    #endif //TEMPLATE_IMPLEMENTATION_HPP 

さて、あなただけの二ヘッダーを含める、またはヘルパーヘッダを行うことができます。

/*template.hpp*/ 
    #ifndef TEMPLATE_HPP 
    #define TEMPLATE_HPP 

    #include "template_declarations.hpp" 

    #endif //TEMPLATE_HPP 
+0

親愛なる黒いモーゼ、 以下は「ガードを含む」の例ですか?また #ifndefの__TRIVIAL_TEMPLATE_H の#define __TRIVIAL_TEMPLATE_H ... #endifの 、 "トランジションユニット" は何ですか? ありがとうございます。 – Giovanni

+0

@ジョヴァンニ:はい、ガードが含まれています。私はあなたのデザインを見ることができるように私の答えを編集しました。 – xinaiz

+0

@Giovanniこれはタイプミスで、BMは翻訳単位を意味していました。コンパイラに渡すファイルを呼び出すための素晴らしい方法です(コンパイラに明示的に渡されないファイルを含めるのではなく)。 –

関連する問題