Denise Moran Denise Moran - 17 days ago 6
C++ Question

c++ templates and polymorphism no sutiable user-defined conversion

Having trouble understanding how (and why) this conversion will not work.

I have class A, class B derived from class A, and class C derived from class B.

class A {};
class B : public A {};
class C : public B {};


I want to make a HashTable that has two template typenames
<K, V>
, where the K is a char and V is a binary search tree template class (
BST<T>
). These BSTs will have typenames
A
,
B
, and
C
.

template <typename K, typename V>
class HashTable {
public:
bool put(K key, V value); // adds key value pair to table
private:
V* table; // table stores values
int size; // size of table
};

template <typename T>
class BST {
public:
bool insert(T item); // adds item to tree
private:
struct BSTNode { // node structure
R data; // item data
BSTNode *left; // left child pointer
BSTNode *right; // right child pointer
};
BSTNode *root; // pointer to root of tree
};


The following code has an error with putting a
BST<C>
in the hashtable because it cannot convert from
BST<C>
to
BST<A>
. However, the last line in main is legal.

int main() {
HashTable<char, BST<A>> inventory;
BST<C> foo;
inventory.put('C', foo);

A *bar= new C();
}


I though because of polymorphism,
BST<C>
is-a
BST<A>
? How can I get around this type difference so I can add BST, BST, and BST to my hashmap?

I've already tried using typedef in the declaration and that did not work.

Answer

The conversion can't happen. BST<C> cannot be converted to a BST<A>, as they are completely different, unrelated classes.

When the template is instanciated, it look like this (grossely):

template <>
struct BST_C {
    bool insert(C item);    // adds item to tree
    // ...
};

template <>
struct BST_A {
    bool insert(A item);    // adds item to tree
    // ...
};

As you can see, there is no relation between the two.


What can you do about this?

Well, you could define a conversion operator, limited to base classes:

template <typename T>
struct BST {
    bool insert(T item);

    // only enable for base classes ------------v
    template<typename To, std::enable_if_t<std::is_base_of<To, T>>* = nullptr>
    operator BST<To> () const {
        // implement the conversion operator...
    }
};

With that conversion operator, your class BST<C> is convertible to BST<B> and BST<A> respectively.