C++ 无法实例化模板 Class

C++ Not able to instantiate a Template Class

让我一步步来说吧。问题是我无法实例化模板 class。请帮助我哪里做错了。

我有一个模板 class 如下:

template <typename K, typename V>
class HashNodeDefaultPrint {

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

然后我有一个属于上述模板的特定 class K = int, V = int

class HashNodePrintIntInt {

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

同样,我还有另一个模板class如下:

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

同样,我有一个特定的 class 与上面的 K = int

模板相匹配
class HashFunctionInteger {

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

现在我创建一个 HashNode 模板化 Class 如下:

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

最后一个 HashMap 模板 class 如下:

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]();
    }    
};

现在在 main() 中,我正在实例化 HashMap class,如下所示:

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

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

但我看到编译错误:

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$ 

当我正确指定特定的 class 名称来定义模板变量时,这个实例化有什么问题?

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]();   <----
    }    
};

您正在尝试新建一个没有默认构造函数的 HashNode 数组。默认构造函数被删除,因为定义了以下构造函数:

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

您可以通过在 class 模板 HashNode 中提供 默认构造函数 来解决此错误,如下所示:

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

这是因为你写的时候需要默认构造函数:

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

在上面的语句中new HashNode<K,V, F2> [TABLE_SIZE]()使用了默认构造函数

需要默认构造函数

如下例所示,我们写new Name[10]()时会使用默认的构造函数。出于同样的原因,您需要 class 模板 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;
}

你想的太多了:-)

如果您已经在使用模板,则可以根据需要专门化它们。那不需要新的 class 名字!

开始于:

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

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

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

而且我希望您不再需要模板默认函数,因为您不再需要手动指定专门的函数。它们现在自动映射到专用版本。

这将在这里结束:

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(){}
};

但是您仍然没有 HashNode 的默认构造函数。也许您生成了一个默认值,或者您在调用中放置了一些默认值,或者完全从构造中传递了这些值。我不知道你想通过默认方式生成它来实现什么。

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