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<class T>
。 2 Why can templates only be implemented in the header file?.
来自 MSVC 的错误消息在这里真的没有帮助。似乎假设您正在尝试显式专业化,但其语法也会有所不同。它应该只是在尝试定义 EratosthenesHashMap::EratosthenesHashMap
时失败并出现语法错误。
@user17732522, 由于class T
是声明类内联的合法方式,编译器可能采用EratosthenesHashMap<class T>
,精确地实例化模板因为这种语法不能是专业化或任何东西,因此使用std::pair
的std::unordered_map
,然后最终看到包含不完整类作为成员的一对将不起作用。错误本身对我来说很有意义,它只有几层深。甚至可能是编译器看到 EratosthenesHashMap<class T>
并回退到“这必须以 ... 类型开始声明”。
@chris 这可能是一种解释,但 MSVC 只接受没有 template<>
介绍的显式特化。如果您将 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<int>
的 main.cpp 文件,并且您在问题中将 EratosthenesHashMap 分解为 .h 和 .cpp,然后 main.cpp 完全独立于 EratosthenesHashMap.cpp 进行编译,并且需要能够链接到 EratosthenesHashMap<int>
的实现,但 EratosthenesHashMap.cpp 不知道它将应用于什么类型,所以这是不可能的。
EratosthenesHashMap.cpp 没有定义一个类;它定义了一个模板;它不能被编译成可以链接的目标文件。
出于这个原因,通常您通过在标头中提供完整实现来使用模板。
【讨论】:
以上是关于C++ 使用具有无序映射的模板类型的主要内容,如果未能解决你的问题,请参考以下文章