Denise Moran Denise Moran - 8 months ago 33
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 (
). These BSTs will have typenames
, and

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

template <typename T>
class BST {
bool insert(T item); // adds item to tree
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
in the hashtable because it cannot convert from
. 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,
? 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 Source

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.