Can a Specialized Template Class Inherit from Another Specialized Template Class? - c++

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).

Related

Error: "does not name a type", when a synonym for a type is used when implementing methods outside the class

Inside the class, I define a synonym for type T* and use it in method signatures. But when implementing methods outside the class, it turns out that the compiler does not understand what Id means. Is it possible to fix the error without moving the implementation of the method inside the class?
template <typename T>
class PriorityCollection {
public:
using Id = T*;
Id Add(T object);
template <typename ObjInputIt, typename IdOutputIt>
void Add(ObjInputIt range_begin, ObjInputIt range_end,
IdOutputIt ids_begin);
bool IsValid(Id id) const;
const T& Get(Id id) const;
void Promote(Id id);
pair<const T&, int> GetMax() const;
pair<T, int> PopMax();
private:
map<size_t, vector<T>> collection;
map<Id, size_t> ids;
Id Add(T object, size_t priority);
};
template <typename T>
Id PriorityCollection<T>::Add(T object, size_t priority) { // <- error: ‘Id’ does not name a type
collection[priority].push_back(move(object));
Id id = &collection[priority].back();
ids[id] = priority;
return id;
}

template functions with multiple templates for specific data type like string?

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
{
}

Reduce code duplication in class template specialization (array<Unique_ptr>)

How to reduce code duplication of a class that is template specialized?
I am trying to create a class (MyArray) that acts like std::vector but receives raw-pointer as parameter in some functions.
Here is a simplified version of it :-
template<class T> class MyArray{
T database[10];
public: T& get(int index){return database[index];}
void set(int index, T t){
database[index]=t;
}
};
template<class T> class MyArray<std::unique_ptr<T>>{
T* database[10];
public: T*& get(int index){return database[index];}
void set(int index, std::unique_ptr<T> t){
T* tmp=t.release();
database[index]=tmp;
}
};
Here is a test:-
class B{};
int main() {
MyArray<B> test1;
MyArray<B*> test2;
MyArray<std::unique_ptr<B>> test3;
test3.set(2,std::make_unique<B>()));
return 0;
}
Question: Please demonstrate an elegant way to reduce the above code duplication in MyArray.
A solution that I wished for may look like :-
template<class T> class MyArray{
using U = if(T=std::uniquePtr<X>){X*}else{T};
U database[10];
public: U& get(int index){return database[index];}
void set(int index, T t){
U u = convert(t);//<-- some special function
database[index]=u;
}
};
There might be some memory leak / corruption. For simplicity, please overlook it.
I just want an idea/rough guide. (no need to provide a full run-able code, but I don't mind)
In real life, there are 20+ function in MyArray and I wish to do the same refactoring for many classes.
Edit: I have (minor) edited some code and tag. Thank AndyG and Jarod42.
Maybe can you delegate the implementation details to a struct you provide to your class, and you specialize this struct, not MyArray:
template <typename T>
struct Policy {
using type = T;
static type convert(T t) { ... }
};
template <typename T>
struct Policy<std::unique_ptr<T>> {
using type = T*;
static type convert(T t) { ... }
};
template <typename T, typename P = Policy<T>>
class MyArray
{
using type = typename P::type;
void set(int index, T t) { type result = P::convert(t); }
};
You might think about using a common base class for the common functionality:
template<class T>
class Base{
protected:
T database[10];
public:
T& get(int index){return database[index];}
};
template<class T>
class MyArray : public Base<T>{
public:
void set(int index, T t){
this->database[index]=t;
}
};
template<class T>
class MyArray<std::unique_ptr<T>> : public Base<T*>
{
public:
void set(int index, std::unique_ptr<T>&& t){
T* tmp=t.release();
this->database[index]=tmp; //a little different
}
};
Demo

derivation template classes

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;
}
};

C++ template definition results in unknown type name

I'm learning about templates in C++. In MyClass.h:
template <class valueType>
void valueToMap(const std::string key, const valueType value);
In MyClass.cpp:
void MyClass::valueToMap(const std::string key, const valueType value) // error
^
{
_map[key] = std::to_string(value);
}
The error is: Unknown type name 'valueType'
I've included the header file, so what am I doing wrong?
It needs to be a template nonetheless
template <typename valueType>
void MyClass<valueType>::valueToMap(const std::string key, const valueType value) // error
^
{
_map[key] = std::to_string(value);
}
However Keep in mind:
Why can templates only be implemented in the header file?
You need to repeat the template during both in declaration and in definition:
template <class valueType>
void MyClass::valueToMap(const std::string key, const valueType value)
{
_map[key] = std::to_string(value);
}
You should add
template <class valueType>
also before method implementation and change
void MyClass:: ...
to
void MyClass<valueType>:: ...
When dealing with templates, you cannot separate the class declaration and class implementation into separate files (at least not without including the .cpp file at the end of the .h file). This is due to how templates are compiled.
The simplest ways to do what you are trying to do is to either inline your functions:
template <class valueType> // assuming this is also at the class level
void valueToMap(const std::string key, const valueType value)
{
_map[key] = std::to_string(value);
}
Or place the implementation after the class declaration in the header file:
template<class valueType>
class MyClass
{
public:
void valueToMap(const std::string key, const valueType value);
};
template<class valueType>
void MyClass<valueType>::valueToMap(const std::string key, const valueType value)
{
_map[key] = std::to_string(value);
}