I have written a template BST class with the usual operations like this:
template <class Key,class T>
class BTree {
public:
BTree():root(0){}//crea un albero vuoto
BTree<Key,T>& treeInsert(const Key& k,const T& val);
BTree<Key,T>& treeDelete(const Key& k);
Node<Key,T>& treeSearch(const Key& k);
Node<Key,T>& treeMinimum();
void treeClear();
protected:
BTree<Key,T>& transplant(Node<Key,T>& n1,Node<Key,T>& n2);
Node<Key,T>* root;
};
I would like to implements a template red-black tree class that inherits from the bst class.
The red-black class should rewrite the insertion and deletion, but I read that methods of a template class can not be virtual, and so do not know how to do this.
As mentioned in comments, you actually can have virtual functions in a template class, and those can be overridden by deriving classes.
Though the better choice IMHO might be, to use a CRTP (aka Static Polymorphism, Policy based design) for such case (as you're already handing on templates). It could look like this
template <class Key,class T,class Derived>
// ^^^^^^^^^^^^^^
class BTree {
public:
BTree():root(0){}//crea un albero vuoto
BTree<Key,T>& treeInsert(const Key& k,const T& val) {
return static_cast<Derived*>(this)->doTreeInsert();
}
BTree<Key,T>& treeDelete(const Key& k) {
return static_cast<Derived*>(this)->doTreeDelete();
}
Node<Key,T>& treeSearch(const Key& k);
Node<Key,T>& treeMinimum();
void treeClear();
protected:
BTree<Key,T>& transplant(Node<Key,T>& n1,Node<Key,T>& n2);
Node<Key,T>* root;
};
Derived classes must implement doTreeInsert() and doTreeDelete() functions accordingly, to let this code compile:
template <class Key,class T>
class RedBlackTree
: public BTree<Key,T,RedBlackTree> {
public:
BTree<Key,T>& doTreeInsert(const Key& k,const T& val) {
// Implement the RB specifics for insert here
return *this;
}
BTree<Key,T>& doTreeDelete(const Key& k) {
// Implement the RB specifics for delete here
return *this;
}
};
Related
#include <iostream>
template <typename T>
struct Node
{
T value;
Node<T>* next;
};
template <typename T>
struct LinkedList
{
// head, tail....
// some implementation...
};
template<
template<typename> typename node,
typename T,
template<typename> typename iterator,
template<typename> typename const_iterator
>
struct SomeComonFunctionsBetweenIterators
{
node<T>* ptr;
// some implementation...
SomeComonFunctionsBetweenIterators(node<T>* ptr) : ptr(ptr) {}
T& operator*() { return ptr->value; }
iterator<T> GetIterator() { return iterator<T>(ptr); }
// doesn't work. want some way like this instead of passing the
// const iterator as a template argument.
//operator const_iterator<T>() { return iterator<const T>(ptr) ; }
operator const_iterator<T>() { return const_iterator<T>(ptr); }
};
template <typename T>
struct LinkedListConstIterator;
template <typename T>
struct LinkedListIterator
: public SomeComonFunctionsBetweenIterators<Node, T, LinkedListIterator, LinkedListConstIterator>
{
LinkedListIterator(Node<T>* ptr)
: SomeComonFunctionsBetweenIterators<Node, T, LinkedListIterator, LinkedListConstIterator>(ptr) {}
// some implementation...
};
template <typename T>
struct LinkedListConstIterator : public LinkedListIterator<T>
{
LinkedListConstIterator(Node<T>* ptr) : LinkedListIterator<T>(ptr) {}
const T& operator*() { return static_cast<const T&>(this->ptr->value); }
};
int main()
{
Node<int> node{ 5, nullptr };
LinkedListIterator<int> it(&node);
std::cout << *it << '\n';
LinkedListConstIterator<int> cit = it;
std::cout << *cit << '\n';
}
In this code I have a linked list and an iterator to it. Also I have a const iterator which inherits from the normal iterator and when dereferenced, returns a const T. The iterator can be for a singly linked list or a doubly linked list and most of the functions in both of them are the same (dereferencing or comparing for example). So I extracted the common functions and put it in a common struct. I want to be able to asign normal iterators to const iterators. So I pass the const iterator to the normal iterator as a template argument and define a conversion operator from the normal iterator to const iterator. This way works but it requires me to always pass the const iterator alongside the normal iterator as a template argument.
Is there any better way to implement const_iterators? instead of passing the const iterator everywhere. How the const_iterators are implemented for example in the STL containers?
How the const_iterators are implemented for example in the STL containers?
You can probably look in your implementation's header files to see how they chose to do it. It will depend on the container type and its internal data structure. But the common pattern I've seen is that there's some private template that can take either non-const T or const T, and that will be used as a base or member of the actual distinct iterator types. One catch is that a specific type from the data structure needs to be used, independently of the type the iterator classes expose. In your example, Node<T> and Node<const T> are not interoperable, so SomeComonFunctionsBetweenIterators could work, but should probably have the node type as a template argument independent of the value type T.
But for an easy way to define iterator types, I always turn to Boost.Iterator's iterator_facade or iterator_adaptor. They take care of a lot of the technical requirements about iterators, letting the author just fill in the behavioral bits. iterator_facade is for implementing something "from scratch", and iterator_adaptor is for the common case of an iterator that contains and wraps another iterator.
The Boost documentation for iterator_facade discusses a way to define related iterator and const_iterator types. (Though their decision to make the iterators interoperable as long as the pointers can convert probably wouldn't be appropriate for iterators from containers.)
Using iterator_facade will also give a bunch of things algorithms may expect of iterators but missing from your code shown, like making std::iterator_traits work, equality and inequality, and other fiddly details.
#include <boost/iterator/iterator_facade.hpp>
#include <type_traits>
template <typename T>
struct Node
{
T value;
Node* next;
};
template <typename NodeType, typename ValueType, typename ContainerType>
class TLinkedListIterator :
public boost::iterator_facade<
TLinkedListIterator<NodeType, ValueType, ContainerType>, // CRTP Derived type
ValueType, // Iterator's value_type
std::forward_iterator_tag // Category
>
{
public:
TLinkedListIterator() : m_node(nullptr) {}
protected:
explicit TLinkedListIterator(NodeType* node) : m_node(node) {}
private:
friend boost::iterator_core_access;
friend ContainerType;
template <typename N, typename V, typename C> friend class TLinkedListIterator;
ValueType& dereference() const { return m_node->value; }
void increment() { m_node = m_node->next; }
// Templating allows comparison between iterator and const_iterator
// in any combination.
template <typename OtherValueType>
bool equal(const TLinkedListIterator<NodeType, OtherValueType, ContainerType>& iter)
{ return m_node == iter.m_node; }
NodeType m_node;
};
template <typename T>
class LinkedList
{
public:
using iterator = TLinkedListIterator<Node<T>, T, LinkedList>;
class const_iterator
: public TLinkedListIterator<Node<T>, const T, LinkedList>
{
private:
using BaseType = TLinkedListIterator<Node<T>, const T, LinkedList>;
public:
const_iterator() = default;
// Converting constructor for implicit conversion from iterator
// to const_iterator:
const_iterator(const iterator& iter)
: BaseType(iter.m_node) {}
protected:
explicit const_iterator(Node<T>* node)
: BaseType(node) {}
friend LinkedList<T>;
};
iterator begin() { return iterator(get_head()); }
iterator end() { return iterator(); }
const_iterator begin() const { return const_iterator(get_head()); }
const_iterator end() const { return const_iterator(); }
const_iterator cbegin() const { return begin(); }
const_iterator cend() const { return end(); }
// ...
};
template <typename Key, typename E>
class BST : public Dictionary<Key, E>
{
.....
E FindHelp(BSTNode<Key, E>*, const Key&) const;
template <typename Key>
std::string FindHelp(BSTNode<Key, std::string> *root, const Key &k) const;
....
};
template <typename Key>
std::string BST<Key, std::string>::FindHelp(BSTNode<Key, std::string> *root, const Key &k) const
{
if (root == nullptr) return "Not Found!"; // Empty tree
// If smaller than the root go left sub tree
if (k < root->key()) return FindHelp(root->Left(), k);
// If bigger than the root go right tree
if (k > root->key()) return FindHelp(root->Right(), k);
// If equal to the root return root value
else return root->Element();
}
I want to add a function dealing with specific data type like std::string, when i wrote my definition like this
error C2244: 'BST::FindHelp': unable to match
function definition to an existing declaration
There is no partial function template specialization. You can only use partial template specialization for class, so you have to partially specialize for BST class first.
template <typename Key, typename E>
class BST : public Dictionary<Key, E>
{
E FindHelp(BSTNode<Key, E>*, const Key&) const;
};
template<typename Key>
class BST<Key, std::string> : public Dictionary<Key, std::string>
{
std::string FindHelp(BSTNode<Key, std::string>*, const Key&) const;
};
template <typename Key>
std::string BST<Key, std::string>::FindHelp(BSTNode<Key, std::string> *root, const Key &k) const
{
}
So I'm using my book from class to create a singly linked list, but i can't get it to compile. I get 20+ errors for syntax and at this point I'm not sure what to do. I must use two classes though.
template <typename E>
class Node {
private:
E elem;
Node<E>* next;
friend class SLinkedList<E>;
};
template <typename E>
class SLinkedList {
public:
SLinkedList();
~SLinkedList();
bool empty() const;
const E& front() const;
void addFront(const E& e);
void removeFront();
I'm creating a container class which implements a double linked list.
template <class T>
class dl_list {
public:
class link {
public:
T* data;
link *prev, *next;
};
class iterator {
link* node;
public:
link* get_node() { return node; }
// ++, --, * operators, etc.
};
// other stuff
};
Pretty neat, I'm having fun with it. But one problem I'm having is when I define my equality operators for the iterator type, I have to do a template specialization.
template <class T>
bool operator==(typename dl_list<T>::iterator& lhv, typename dl_list<T>::iterator rhv) {
return lhv.get_node() == rhv.get_node();
}
will not work, I have to specialize it like so:
bool operator==(typename dl_list<int>::iterator& lhv, typename dl_list<int>::iterator rhv) {
return lhv.get_node() == rhv.get_node();
}
for every type I want to use it for, which is annoying for obvious reasons. How do I get around this?
Make it a member of the iterator class:
bool operator==( const interator& other ) const
{
return node == other.node;
}
You can't. The compiler cannot know that some T is a nested type of some other U. Consider
template<> class dl_list<float> {
public:
typedef dl_list<int>::iterator iterator;
};
You have to take the iterator type directly as the template parameter, or define it as a member of the iterator class, or define the iterator class outside dl_list and simply make a typedef for it inside dl_list.
Easiest cleanest way is to define the operator inside the iterator class:
class iterator
{
public:
...
friend bool operator==(iterator& lhs, iterator& rhs)
{
return lhs.get_node() == rhs.get_node();
}
};
(Bit of a code smell here - I'd have expected get_node() to have a const version, allowing the operator== to accept parameters by const reference...)
I first defined
class Hash
{
};
Then a specialization of Hash.
template <class T>
class Hash<int, T>
{
public:
Hash(int slotN = 11);
bool insert(int key, T val);
bool remove(int key);
bool contains(int key);
bool query(int key, T& val) ;
protected:
// Basic Variables of the Hash Model.
list<int>* slot;
list<T>* slotVal;
int slotN;
};
I want to use this specialized version of Hash
to implement another specialization: Hash of
String-Valued Keys.
template <class T>
class Hash<string, T> : public Hash<int, T>
{
public:
Hash(int slotN);
bool insert(string key, T val);
bool remove(string key);
bool contains(string key);
bool query(string key, T& val) ;
private:
// Calculate the String's Hash Key.
int str2key( string key);
};
But it seemed I cannot access fields in the class Hash. Why?
When you say "I cannot access fields in the class Hash" I guess you mean, that you when you are using Hash<string, T> (for some type T) that you cannot call the overloaded functions from Hash<int, T>. The reason for this is name hiding: when you overload a member function in a derived class, all members with the same name in the base class are hidden unless you make them explicitly available. The way to do it is a using declaration:
template <class T>
class Hash<string, T> : public Hash<int, T>
{
public:
Hash(int slotN);
using Hash<int, T>::insert;
using Hash<int, T>::remove;
using Hash<int, T>::contains;
using Hash<int, T>::query;
bool insert(string key, T val);
bool remove(string key);
bool contains(string key);
bool query(string key, T& val) ;
private:
// Calculate the String's Hash Key.
int str2key( string key);
};
If you just need to access the base class members from your derived class's implementation, you can also access the names using qualification with the class name. For example:
template <typename T>
bool Hash<string, T>::insert(string key, T val) {
return this->Hash<int, T>::insert(this->str2key(key, val);
}
Thinking a bit more about the question, there is another potential issue: If you access the data members in the base class you need to make sure that the compiler considers the name a dependent name. Otherwise it is looked up in phase one and won't the names in the base because the can only be found in phase two:
template <typename T>
bool Hash<string, T>::insert(string key, T val) {
int n0 = slotN; // doesn't work: looked up in phase 1
int n1 = this->slotN; // OK: name is dependent
int n2 = Hash<int, T>::slotN; // OK, too
}
Personally, I wouldn't publicly derive from a class with a different key but I assume you have your reasons. BTW, I assume that your primary declaration of Hash looks something like this although it doesn't matter for the problem, really:
template <typename K, typename T>
class Hash;
(if it doesn't have any members, I would rather not define it, either).