2011-12-15 5 views
1

Accelerated C++の第11章では、STLのベクトルクラスの簡略版を例として、テンプレートクラスの実装について説明しています。エクササイズ11-6では、.erase().clear()のメソッドをクラスに追加したいので、最初に最終コードをブックから直接コピーしてコンパイルしようとしましたが、失敗しました。その後、すべての関数定義を.hファイルに移動し(必要に応じてVec<T>::などを削除して)、main.cppをコンパイルしました。ここで簡略化されたC++ベクタークラスのコピーの実装 -

は、私のコードのすべてです:

main.cppに

#include <iostream> 
#include "Vec.h" 

using std::cout; 
using std::endl; 

int main() 
{ 
    Vec<int> v; 
    for (int i = 1; i < 10; ++i) 
     v.push_back(i); 

    for(Vec<int>::const_iterator iter = v.begin(); 
     iter != v.end(); ++iter) 
     cout << *iter << endl; 

    return 0; 
} 

Vec.h

#ifndef GUARD_Vec_h 
#define GUARD_Vec_h 

#include <cstddef> 
#include <memory> 

template <class T> class Vec { 
public: 
    // member variables 
    typedef T* iterator; 
    typedef const T* const_iterator; 
    typedef std::size_t size_type; 
    typedef T value_type; 
    typedef T& reference; 
    typedef const T& const_reference; 

    // constructors + destructors 
    Vec() { create(); } 
    explicit Vec(size_type n, const T& t = T()) { create(n, t); } 
    Vec(const Vec& v) { create(v.begin(), v.end()); } 
    ~Vec() { uncreate(); } 

    // methods 
    T& operator[](size_type i) { return data[i]; } 
    const T& operator[](size_type i) const { return data[i]; } 

    void push_back(const T& t) { 
     if (avail == limit) 
      grow(); 
     unchecked_append(t); 
    } 

    size_type size() const { return avail - data; } 

    iterator begin() { return data; } 
    const_iterator begin() const { return data; } 

    iterator end() { return avail; } 
    const_iterator end() const { return avail; } 

private: 
    iterator data; 
    iterator avail; 
    iterator limit; 

    std::allocator<T> alloc; 

    void create(); 
    void create(size_type, const T&); 
    void create(const_iterator, const_iterator); 

    void uncreate(); 

    void grow(); 
    void unchecked_append(const T&); 
}; 

#endif GUARD_Vec_h 

Vec.cpp

#include <algorithm> 
#include <cstddef> 
#include <memory> 
#include "Vec.h" 

using std::allocator; 
using std::max; 
using std::uninitialized_copy; 
using std::uninitialized_fill; 
using std::ptrdiff_t; 

template <class T> void Vec<T>::create() 
{ 
    data = avail = limit = 0; 
} 

template <class T> void Vec<T>::create(size_type n, const T& val) 
{ 
    data = alloc.allocate(n); 
    limit = avail = data + n; 
    uninitialized_fill(data, limit, val); 
} 

template <class T> void Vec<T>::create(const_iterator i, const_iterator j) 
{ 
    data = alloc.allocate(j - i); 
    limit = avail = uninitialized_copy(i, j, data); 
} 

template <class T> void Vec<T>::uncreate() 
{ 
    if (data) { 
     iterator it = avail; 
     while (it != data) 
      alloc.destroy(--it); 

     alloc.deallocate(data, limit - data); 
    } 

    data = limit = avail = 0; 
} 

template <class T> void Vec<T>::grow() 
{ 
    size_type new_size = max(2 * (limit - data), ptrdiff_t(1)); 

    iterator new_data = alloc.allocate(new_size); 
    iterator new_avail = uninitialized_copy(data, avail, new_data); 

    uncreate(); 

    data = new_data; 
    avail = new_avail; 
    limit = data + new_size; 
} 

template <class T> void Vec<T>::unchecked_append(const T& val) 
{ 
    alloc.construct(avail++, val); 
} 

はなぜこのコンパイルを行います?

+3

テンプレート定義をヘッダファイルに入れなければならない理由を説明していないと考えるのは非常に難しいです。いずれにせよ、[this](http://www.parashift.com/c++-faq -lite/templates.html#faq-35.15)。 – ildjarn

+0

著者は.hと.cppファイルに分割された 'Vec'を入れたようです。そうだとすれば、彼はかわいらしいコンパイラを持っていなければなりません! –

+0

Hm、たぶん私は間違っている/間違っているかもしれないが、私はそれがそこにあると思うが、そのことを言及している本を思い出すことはない(加速的なC++は全体的に本当に良い本だと思われる)...助けてくれてありがとう! * EDIT * 2番目の考えで..本はテンプレートが最初に導入されたときにこれをいくつかの章に言及しました。忘れてしまった私のせいです。 – adelbertc

答えて

0

問題は、すべてのテンプレート関数に問題があります。テンプレート関数を記述すると、コンパイラはテンプレートをインスタンス化します。つまり、コードを実行するために必要な型の関数の特定のバージョンを作成します。あなたが電話をするとき

Vec<int> v; 

コンパイラはVecとあなたが呼び出すそのタイプの関数のコードを作成します。コンパイラーは、主ファイルのコードを作成する際にテンプレート化された関数定義にアクセスする必要があります。これは、他のファイルをリンクする前に、オブジェクトファイルに対してどのようなコードを作成するかを知る必要があるからです。

関連する問題