Home > other >  C Not able to instantiate a Template Class
C Not able to instantiate a Template Class

Time:01-04

Let me put it step by step. The problem is I am not able to instantiate a Template class. Pls help where am i doing wrong.

I have a template class as below :

template <typename K, typename V>
class HashNodeDefaultPrint {

public:
    void operator()(K key, V value) {}
};

Then I have a specific class that belongs to the above template for K = int, V = int

class HashNodePrintIntInt {

public:
    void operator()(int key, int value) {
        printf ("k = %d, v = %d", key, value);
    }
};

Similarly, I have another template class as below :

template <typename K>
class defaultHashFunction {
   public:
    int operator()(K key) {
        return 0;
    }
};

Again, I have a specific class which matches the above template for K = int

class HashFunctionInteger {

public:
    int operator()(int key) {
        return key % TABLE_SIZE;
    }
};

Now I create a HashNode templated Class as below :

template <typename K, typename V, typename F = HashNodeDefaultPrint<K, V>>
class HashNode {

public:
    K key;
    V value;
    F printFunc;
    HashNode *next;
    HashNode(K key, V value, F func) {
        this->key = key;
        this->value = value;
        next = NULL;
    } 
};

And finally a HashMap Templates class as Below :

template <typename K, typename V, typename F = defaultHashFunction<K>, typename F2 = HashNodeDefaultPrint<K,V>>
class HashMap {

private:
    HashNode<K, V, F2> *table_ptr;
    F hashfunc;
public:
    HashMap() {
        table_ptr = new HashNode<K,V, F2> [TABLE_SIZE]();
    }    
};

Now in main(), i am instantiating the HashMap class as below :

int
main(int argc, char **argv) {

    HashMap<int, int, HashFunctionInteger, HashNodePrintIntInt> hmap;
    return 0;
}

but i am seeing compilation error :

vm@ubuntu:~/src/Cplusplus/HashMap$ g   -g -c hashmap.cpp -o hashmap.o
hashmap.cpp: In instantiation of ‘HashMap<K, V, F, F2>::HashMap() [with K = int; V = int; F =         HashFunctionInteger; F2 = HashNodePrintIntInt]’:
hashmap.cpp:157:65:   required from here
hashmap.cpp:107:21: error: no matching function for call to ‘HashNode<int, int,     HashNodePrintIntInt>::HashNode()’
  107 |         table_ptr = new HashNode<K,V, F2> [TABLE_SIZE]();
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
hashmap.cpp:30:9: note: candidate: ‘HashNode<K, V, F>::HashNode(K, V, F) [with K = int; V = int; F = HashNodePrintIntInt]’
   30 |         HashNode(K key, V value, F func) {
      |         ^~~~~~~~
hashmap.cpp:30:9: note:   candidate expects 3 arguments, 0 provided
hashmap.cpp:27:7: note: candidate: ‘constexpr HashNode<int, int,     HashNodePrintIntInt>::HashNode(const HashNode<int, int, HashNodePrintIntInt>&)’
   27 | class HashNode {
      |       ^~~~~~~~
hashmap.cpp:27:7: note:   candidate expects 1 argument, 0 provided
hashmap.cpp:27:7: note: candidate: ‘constexpr HashNode<int, int,     HashNodePrintIntInt>::HashNode(HashNode<int, int, HashNodePrintIntInt>&&)’
hashmap.cpp:27:7: note:   candidate expects 1 argument, 0 provided
vm@ubuntu:~/src/Cplusplus/HashMap$ 

What is wrong with this instantiation when I am correctly specifying the specific class names to define template variables?

CodePudding user response:

You think much to complicated :-)

If you already use templates, you can specialize them if you need. That did NOT require new class names!

Starting with:

template <typename K, typename V>
struct HashNodePrint { 
    void operator()(K key, V value) {} 
};

// and specialize for int,int:
template<>
struct HashNodePrint<int,int> {
    void operator()(int key, int value) {
        printf ("k = %d, v = %d", key, value);
    }
};

The same for

template <typename K>
struct HashFunction {
    int operator()(K key) {
        return 0;
    }
};

template <>
struct HashFunction<int> {
    int operator()(int ) {
        return 0;
    }
};

And I expect you do not longer need the template default funcs, as you have not longer the need to manually specify the specialized functions. They are now automatically mapped to the specialized version.

This will end up here:

template <typename K, typename V>
class HashNode {

    public:
        K key;
        V value;
        HashFunction<K> printFunc;
        HashNode *next;
        HashNode(K key, V value) {
            this->key = key;
            this->value = value;
            next = NULL;
        }
        HashNode(){}
};

But still you have no default constructor for your HashNode. Maybe you generate a default one OR you put some default values in the call or pass the values down from construction at all. I have no idea what you want to achieve by generating it in a defaulted way.

template <typename K, typename V >
class HashMap {
    private:
        HashNode<K, V> *table_ptr;
        HashFunction<K> hashfunc;
    public:
        HashMap(/* put maybe a container type here */) {
            // no idea how big your TABLE_SIZE will be. 
            // 
            table_ptr = new HashNode<K,V> [TABLE_SIZE]{ /* and forward as needed */};
        }
};

int main() {

    HashMap<int, int> hmap{ /* pass args maybe in container or std::initializer_list */;
    return 0;
}

CodePudding user response:

template <typename K, typename V, typename F = defaultHashFunction<K>, typename 
F2 = HashNodeDefaultPrint<K,V>>
class HashMap {

private:
    HashNode<K, V, F2> *table_ptr;
    F hashfunc;
public:
    HashMap() {
        table_ptr = new HashNode<K,V, F2> [TABLE_SIZE]();   <----
    }    
};

You are trying to new an array of HashNode<K, V, F2> which does not have a default constructor. The default constructor is deleted because the following constructor was defined:

HashNode(K key, V value, F func) {
    this->key = key;
    this->value = value;
    next = NULL;
} 

CodePudding user response:

You can solve this error by providing a default constructor inside class template HashNode as shown below:

template <typename K, typename V, typename F = HashNodeDefaultPrint<K, V>>
class HashNode {

public:
    HashNode(K key, V value, F func) {
        this->key = key;
        this->value = value;
        next = NULL;
    } 
    HashNode() = default;  //DEFAULT CONSTRUCTOR ADDED
};

This is because you need the default constructor when you wrote:

table_ptr = new HashNode<K,V, F2> [TABLE_SIZE](); //<--- default constructor needed here

In the above statement new HashNode<K,V, F2> [TABLE_SIZE]() uses the default constructor.

Need For Default Constructor

As shown in the below given example, the default constructor will be used when we write new Name[10](). For the same reason you need the default constructor for class template HashNode.

struct Name 
{
  
  Name()
  {
      std::cout<<"default constructor called"<<std::endl;
  }
  ~Name()
  {
      std::cout<<"destructor called"<<std::endl;
  }
};

int main() {

   Name *ptr = new Name[10](); //this will use the default constructor
   
   delete []ptr;
   return 0;
}

  • Related