LINUX.ORG.RU

Вспоминая C++. Проблемы с линковкой template'ов


0

0

В общем попросили меня вспомнить C++ и написать курсовую работу ...
cat btree.h
#ifndef _BTREE_H_
#define _BTREE_H_
#include "btreenode.h"
template<class T>
class BTree
{
	private:
		BTreeNode<T> *root;
		bool addNode(BTreeNode<T> *node, const T &value);
		bool searchNode(BTreeNode<T> *node, const T &value, T &result);
	public:
		BTree() {root = 0;};
		bool add(const T &value);
//		bool del(const T &value);
		bool search(const T &value, T &result);
};

#endif

cat btree.cpp
...
template <class T>
bool BTree<T>::add(const T &value)
{
	if (root != 0)
		return addNode(root, value);
	root = new BTreeNode<T>(value);
	return true;
};
...

cat main.cpp
#include "btreedata.h"
#include "btree.h"
#include <string>
using namespace std;
int main(int argc, char *argv[])
{
	BTree<BTreeData> tree;
	BTreeData val1(string("test"), string("test"));
	bool r = tree.add(val1);
	return 0;
};

g++ btree.cpp main.cpp -o btree
/tmp/ccy6f1Vm.o: In function `main':
main.cpp:(.text+0xd0): undefined reference to `BTree<BTreeData>::add(BTreeData const&)'
collect2: выполнение ld завершилось с кодом возврата 1

Расскажите что я делаю не так?
anonymous

Re: Вспоминая C++. Проблемы с линковкой template'ов

Компилятор не создал конкретизацию шаблона.

Перенеси тело BTree<T>::add в btree.h

tailgunner ★★★★★ ()

Re: Вспоминая C++. Проблемы с линковкой template'ов

Спасибо, теперь g++ нормально съел этот код. Но как-то это не красиво получается ... может просветишь в чем причина? Линки приветствуются:)
А, да, теперь появилась новая проблема ... до изменений g++ на следующие строки не ругался, а сейчас начал и я опять не могу понять в чем причина:)

g++ main.cpp -o btree
btree.h: In member function &#8216;bool BTree<T>::addNode(BTreeNode<T>*, const T&) [with T = BTreeData]&#8217;:
btree.h:41:   instantiated from &#8216;bool BTree<T>::add(const T&) [with T = BTreeData]&#8217;
main.cpp:11:   instantiated from here
btree.h:14: ошибка: passing &#8216;const BTreeData&#8217; as &#8216;this&#8217; argument of &#8216;bool BTreeData::operator<(const BTreeData&)&#8217; discards qualifiers
btree.h:23: ошибка: passing &#8216;const BTreeData&#8217; as &#8216;this&#8217; argument of &#8216;bool BTreeData::operator>(const BTreeData&)&#8217; discards qualifiers

cat btreedata.h
#ifndef _BTREEDATA_H_
#define _BTREEDATA_H_

#include <string>

using namespace std;

class BTreeData
{
	private:
		string pkey;
		string pvalue;
	public:
		BTreeData(){};
		BTreeData(const string &key, const string &value) {pkey = key; pvalue = value;};
		void setKey(string &key) {pkey = key;};
		void setValue(string &value) {pvalue = value;};
		string &getKey() {return pkey;};
		string &getValue() {return pvalue;};
		bool operator > (const BTreeData &value) {return (value.pkey > this->pkey);};
		bool operator < (const BTreeData &value) {return (value.pkey < this->pkey);};
		bool operator == (BTreeData &value) {return (value.pkey == pkey);};
};

#endif

anonymous ()

Re: Вспоминая C++. Проблемы с линковкой template'ов

операторы должны быть объявлены константными, чтоб принимать константный this. Видимо где-от в addNode вызывается operator< с const левым аргуметом.

константный оператор объявлять так:

bool operator > (const BTreeData &value) const {return (value.pkey > this->pkey);};

Раньше ошибки не было т.к. template не инстанциировался

Если список типов для которых template будет использоваться известен, то для сокращени явремени компиляции можно таки не запихивать всё в .h файл, а для каждого из типов T1 T2 Tn написать в btree.cpp явное указание компилятору сгенерить код (т.е. явное инстанциирование):

template class BTree<T1>;

template class BTree<T2>;

....

template class BTree<Tn>;

GPFault ★★ ()

Re: Вспоминая C++. Проблемы с линковкой template'ов

Для генерации тела функции add компилятор должен одновременно видеть ее тело и тип, которым оно конкретизируется. Когда add была в другом файле, компилятор не видел ее тела, и сгенерировал внешнюю ссылку на конкретизированную функцию (в надежде, что кто-то позаботился ее сгенерировать). После переноса тела в *.h-файл, компилятор видит всё, что нужно для генерации, и выполняет ее.

Насчет ошибки - похоже, ты вызываешь не-константный operator< на константном объекте. Сделай BTreeData::operator< (и >) константными.

tailgunner ★★★★★ ()

Re: Вспоминая C++. Проблемы с линковкой template'ов

tailgunner, GPFault спасибо, все победил:)
И еще, может посоветуете хорошую книжку/учебник по cpp, что бы там были описаны и такие тонкости. Желательно на русском и в бумажном виде:)

anonymous ()

Re: Вспоминая C++. Проблемы с линковкой template'ов

ЕМНИП по стандарту в таком случае надо в cpp писать export template<...>... но g++ export не умеет

Begemoth ★★★★★ ()

Re: Вспоминая C++. Проблемы с линковкой template'ов

Я учил Си++ во времена, когда учебник по нему был единственный - "Язык программирования Си++" Б.Страуструпа, 1-е издание :) Сейчас вышло уже 3-е, на бумаге и русском языке. Неплохая книга, хотя разделы, посвященные Си, можно пропустить.

tailgunner ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.