歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> C++模板函數聲明定義分離編譯錯誤詳解

C++模板函數聲明定義分離編譯錯誤詳解

日期:2017/3/1 9:55:02   编辑:Linux編程

今天看到accelerated c++上有個簡單的vector容器的實現Vec,就再vs2008上編譯了下:

///// Vec.h

#ifndef GUARD_VEC_H

#define GUARD_VEC_H

#include <iostream>

#include <iterator>

#include <memory>

//#include <xmemory>

template <class T>

class Vec

{

public:

typedef T* iterator;

typedef const T* const_iterator;

typedef size_t size_type;

typedef T value_type;

typedef T& reference;

typedef const T& const_reference;

Vec() {create();} //默認的構造函數

explicit Vec(size_type n,const T& t=t()) {create(n,t);} //單參數或者兩個參數構造函數

Vec(const Vec& v) {create(v.begin(),v.end());} //拷貝構造函數

Vec& operator=(const Vec&); //賦值構造函數

~Vec() {uncreate();} //析構函數

size_type size() { return avail-data; } //定義類的大小,ptrdiff_t自動轉化成size_t

void push_back(const T& t)

{

if (avail==limit)

{

grow();

}

unchecked_append(t);

}

//重載【】

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

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

//定義begin和end,都有兩個版本

iterator begin() {return data;}

const_iterator begin() const {return data;}

iterator end() {return avail;}

const_iterator end() const {return avail;}

protected:

private:

iterator data; //Vec中得初始值

iterator avail; //Vec中得結束值

iterator limit; //Vec中空間分配的結束值

std::allocator<T> alloc; //注意此處std

//創造函數,負責內存管理

void create();

void create(size_type,const T&);

void create(const_iterator,const_iterator);

//銷毀元素,返回內存

void uncreate();

//支持push_back函數

void grow();

void unchecked_append(const T&);

};

#endif


//// Vec.cpp

#include <iostream>

#include "Vec.h"

//#pragma comment(lib,"ws2_32.lib")

using namespace std;

//拷貝構造函數

template <class T>

Vec<T>& Vec<T>::operator=(const Vec& v)

{

if (&v!=this) //檢查是否為自我賦值,很重要,必須有

{

uncreate(); //清空左值的元素

create(v.begin(),v.end()); //拷貝元素到左值

}

return *this;

}

//push_back函數中內存增長策略函數

template <class T>

void Vec<T>::grow()

{

size_type new_size=max(2*(limit-data),ptrdiff_t(1)); //防止剛開始內存空間為0的情況

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)

{

//在未初始化的空間構建一個對象,參數1插入對象的位置指針,參數2需要添加的對象

alloc.construct(avail++,val);

}

//申請內存的函數create

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) //如果data是0,我們不需要做什麼工作

{

iterator it=avail;

while (it!=data)

alloc.destroy(--it); //銷毀沒個元素,為了與delete行為一致,采用從後向前遍歷

alloc.deallocate(data,limit-data); //內存釋放,函數需要一個非零指針

//因此,檢測data是否為零

}

data=limit=avail=0;

}


//// 測試的main函數

#include <iostream>

#include "Vec.h"

using namespace std;

int main()

{

Vec<int> a;

Vec<int> b;

a.push_back(12);

b=a;

return 0;

}

結果編譯後出現下面錯誤:

1>------ 已啟動生成: 項目: Accelerated, 配置: Debug Win32 ------
1>正在編譯...
1>Vec.cpp
1>Vec_example.cpp
1>正在生成代碼...
1>正在鏈接...
1>Vec_example.obj : error LNK2001: 無法解析的外部符號 "public: class Vec<int> & __thiscall Vec<int>::operator=(class Vec<int> const &)" (??4?$Vec@H@@QAEAAV0@ABV0@@Z)
1>Vec_example.obj : error LNK2001: 無法解析的外部符號 "private: void __thiscall Vec<int>::create(void)" (?create@?$Vec@H@@AAEXXZ)
1>Vec_example.obj : error LNK2001: 無法解析的外部符號 "private: void __thiscall Vec<int>::uncreate(void)" (?uncreate@?$Vec@H@@AAEXXZ)
1>Vec_example.obj : error LNK2001: 無法解析的外部符號 "private: void __thiscall Vec<int>::unchecked_append(int const &)" (?unchecked_append@?$Vec@H@@AAEXABH@Z)
1>Vec_example.obj : error LNK2001: 無法解析的外部符號 "private: void __thiscall Vec<int>::grow(void)" (?grow@?$Vec@H@@AAEXXZ)
1>E:\360data\重要數據\我的文檔\Visual Studio 2008\Projects\Accelerated\Debug\Accelerated.exe : fatal error LNK1120: 5 個無法解析的外部命令
1>生成日志保存在“file://e:\360data\重要數據\我的文檔\Visual Studio 2008\Projects\Accelerated\Accelerated\Debug\BuildLog.htm”
1>Accelerated - 6 個錯誤,0 個警告
========== 生成: 成功 0 個,失敗 1 個,最新 0 個,跳過 0 個 ==========

上面問題不知道怎麼解決,就開始google解決方案: 模板不支持分離編譯, 把你模板類的聲明和實現放到.h文件裡面 。按照這個說的把.h和.cpp文件合並後,果然可以了。

Copyright © Linux教程網 All Rights Reserved