C++ 使用具有无序映射的模板类型

Posted

技术标签:

【中文标题】C++ 使用具有无序映射的模板类型【英文标题】:C++ using template type with unordered map 【发布时间】:2021-12-30 19:05:50 【问题描述】:

我是 C++ 新手,所以这可能是一个简单的错误,但是这段代码现在给我带来了几个小时的问题。我真的只是不确定下一步该尝试什么。

EratosthenesHashMap.h

#pragma once

#include <unordered_map>
#include <boost/functional/hash.hpp>
#include "SieveOfEratosthenes.h"

template<class T>
class EratosthenesHashMap


public:
    EratosthenesHashMap(SieveOfEratosthenes& sieve);
    ~EratosthenesHashMap();

    unsigned int addValue(T& value);
    unsigned int getPrime(T& value) const;

private:
    SieveOfEratosthenes *sieve;
    std::unordered_map<T, unsigned int, boost::hash<T>> valueMap;
;

EratosthenesHashMap.cpp

#include "EratosthenesHashMap.h"

EratosthenesHashMap<class T>::EratosthenesHashMap(SieveOfEratosthenes& sieve) 

    this->sieve = &sieve;
;

unsigned int EratosthenesHashMap<T>::addValue(T& value)

    return 0;


unsigned int EratosthenesHashMap<T>::getPrime(T& value) const

    return 0;

错误:

EratosthenesHashMap.cpp
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30037\include\utility(331,10): error C2079: 'std::pair<const T,unsigned int>::first' uses undefined class 'T'
1>        with
1>        [
1>            T=T
1>        ]
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30037\include\xhash(305): message : see reference to class template instantiation 'std::pair<const T,unsigned int>' being compiled
1>        with
1>        [
1>            T=T
1>        ]
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30037\include\xhash(304): message : while compiling class template member function 'void std::_Hash_vec<std::allocator<std::_List_unchecked_iterator<std::_List_val<std::_List_simple_types<_Ty>>>>>::_Tidy(void) noexcept'
1>        with
1>        [
1>            _Ty=std::pair<const T,unsigned int>
1>        ]
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30037\include\xhash(313): message : see reference to function template instantiation 'void std::_Hash_vec<std::allocator<std::_List_unchecked_iterator<std::_List_val<std::_List_simple_types<_Ty>>>>>::_Tidy(void) noexcept' being compiled
1>        with
1>        [
1>            _Ty=std::pair<const T,unsigned int>
1>        ]
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30037\include\xhash(1933): message : see reference to class template instantiation 'std::_Hash_vec<std::allocator<std::_List_unchecked_iterator<std::_List_val<std::_List_simple_types<_Ty>>>>>' being compiled
1>        with
1>        [
1>            _Ty=std::pair<const T,unsigned int>
1>        ]
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30037\include\unordered_map(69): message : see reference to class template instantiation 'std::_Hash<std::_Umap_traits<_Kty,_Ty,std::_Uhash_compare<_Kty,_Hasher,_Keyeq>,_Alloc,false>>' being compiled
1>        with
1>        [
1>            _Kty=T,
1>            _Ty=unsigned int,
1>            _Hasher=boost::hash<T>,
1>            _Keyeq=std::equal_to<T>,
1>            _Alloc=std::allocator<std::pair<const T,unsigned int>>
1>        ]
1>C:\Users\jpsie\source\repos\EratosthenesContainer\EratosthenesContainer\EratosthenesHashMap.h(20): message : see reference to class template instantiation 'std::unordered_map<T,unsigned int,boost::hash<T>,std::equal_to<T>,std::allocator<std::pair<const T,unsigned int>>>' being compiled
1>        with
1>        [
1>            T=T
1>        ]

我正在尝试创建一个 hashmap 作为键类型为 T、值类型为 unsigned int 的成员变量,并且我正在将 boost 库用于哈希函数。

【问题讨论】:

1.您忘记了每个方法定义之前的template&lt;class T&gt;。 2 Why can templates only be implemented in the header file?. 来自 MSVC 的错误消息在这里真的没有帮助。似乎假设您正在尝试显式专业化,但其语法也会有所不同。它应该只是在尝试定义 EratosthenesHashMap::EratosthenesHashMap 时失败并出现语法错误。 @user17732522, 由于class T 是声明类内联的合法方式,编译器可能采用EratosthenesHashMap&lt;class T&gt;,精确地实例化模板因为这种语法不能是专业化或任何东西,因此使用std::pairstd::unordered_map,然后最终看到包含不完整类作为成员的一对将不起作用。错误本身对我来说很有意义,它只有几层深。甚至可能是编译器看到 EratosthenesHashMap&lt;class T&gt; 并回退到“这必须以 ... 类型开始声明”。 @chris 这可能是一种解释,但 MSVC 只接受没有 template&lt;&gt; 介绍的显式特化。如果您将 class T 更改为 T 您会得到相同的错误,并且使用 int 而不是 T 它可以愉快地编译。 @user17732522,很有趣。在那种情况下,我撤销我所说的话。这似乎是一个令人高兴的巧合,它符合这种逻辑。 【参考方案1】:

在头文件和 .cpp 文件之间拆分模板类并且易于调用者使用是相当困难的。相反,将整个模板类内联到EratosthenesHashMap.h

template<class T>
class EratosthenesHashMap


public:
    EratosthenesHashMap(SieveOfEratosthenes& sieve)
    
        this->sieve = &sieve;
    
    ~EratosthenesHashMap()
    
    

    unsigned int addValue(T& value)
    
        return 0;
    

    unsigned int getPrime(T& value) const
    
        return 0;
    

private:
    SieveOfEratosthenes* sieve;
    std::unordered_map<T, unsigned int, boost::hash<T>> valueMap;
;

【讨论】:

【参考方案2】:

定义模板类成员的方式是

template<class T>
EratosthenesHashMap<T>::EratosthenesHashMap(SieveOfEratosthenes& sieve) 

    this->sieve = &sieve;
;

除此之外,您可能应该在头文件中定义模板,否则它们将只能在同一个 cpp 文件中使用。

见Why can templates only be implemented in the header file?

【讨论】:

对,剪得太多了……【参考方案3】:

您的代码无法编译的原因是您无法以典型方式将类模板分解为 .h 文件和 .cpp 文件。

假设您有一个使用 EratosthenesHashMap&lt;int&gt; 的 main.cpp 文件,并且您在问题中将 EratosthenesHashMap 分解为 .h 和 .cpp,然后 main.cpp 完全独立于 EratosthenesHashMap.cpp 进行编译,并且需要能够链接到 EratosthenesHashMap&lt;int&gt; 的实现,但 EratosthenesHashMap.cpp 不知道它将应用于什么类型,所以这是不可能的。

EratosthenesHashMap.cpp 没有定义一个类;它定义了一个模板;它不能被编译成可以链接的目标文件。

出于这个原因,通常您通过在标头中提供完整实现来使用模板。

【讨论】:

以上是关于C++ 使用具有无序映射的模板类型的主要内容,如果未能解决你的问题,请参考以下文章

C++ Primer 5th笔记(chap 16 模板和泛型编程)类模板特例化

模板类运算符重载多个类型名 C++

C++ STL 集的复杂模板参数类型

在 C++ 中使用具有相同类的多个模板

C ++模板堆栈映射/多映射[关闭]

为啥此代码有效(具有无效非模板函数的 C++ 模板类)? [复制]