[英]Cannot specialize std::hash to store custom type in unordered_map
我正在尝试使用共享库中定义的类的实例作为unordered_map的键。 但是,当我以正常正确的方式专门针对名为Tile的此类的std :: hash模板时,由于某种原因,编译器会不断抱怨:
/usr/include/c++/7/bits/hashtable_policy.h:87: error: no match for call to ‘(const std::hash<Tile>) (const Tile&)’
noexcept(declval<const _Hash&>()(declval<const _Key&>()))>
~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
这是我定义std :: hash(pathfinder.h)专业化的头文件:
#ifndef PATHFINDER_H
#define PATHFINDER_H
#include <vector>
#include <unordered_set>
#include <unordered_map>
#include <memory>
#include "Libworld/world.h"
#include "node.h"
#include "nodifier.h"
#include "pathgenerator.h"
namespace std {
template <>
struct hash < Tile > {
public:
size_t operator() ( const Tile & theTile ) const noexcept {
return ( ( 32768 * theTile.getXPos ( ) ) + theTile.getYPos ( ) );
}
size_t operator() ( const Tile * theTile ) const noexcept {
return ( ( 32768 * theTile->getXPos ( ) ) + theTile->getYPos ( ) );
}
};
template <>
struct equal_to < Tile > {
bool operator ( ) ( const Tile & lhs, const Tile & rhs ) const {
return ( lhs == rhs );
}
};
}
class Pathfinder {
private:
std::vector < std::unique_ptr < Tile > > theWorld;
QString theWorldName;
int worldRows, worldColumns, numberOfEnemies, numberOfHealthPacks;
std::unordered_set < std::shared_ptr < Node > > worldNodes;
std::unordered_map < Tile, bool > hasEnemyOrHealthPack;
std::shared_ptr < Nodifier > worldNodifier;
std::shared_ptr < PathGenerator > worldPathGenerator;
Tile startingTile, endingTile;
std::shared_ptr < Node > startingNode, endingNode;
// unsigned int findTileWithLocation ( std::vector < std::unique_ptr < Node > > * nodesList, int x, int y ) const;
void generateNodes ( );
void generateHasEnemyOrHealthPack ( World worldLoader, int numberOfEnemies, int numberOfHealthPacks );
public:
Pathfinder ( QString initialWorldName,
Tile initialStartingTile,
Tile initialEndingTile,
std::shared_ptr < Nodifier > initialWorldNodifier,
std::shared_ptr < PathGenerator > initialWorldPathGenerator,
int initialNumberOfEnemies,
int initialNumberOfHealthPacks );
QString getWorldName ( ) const;
void loadNewWorld ( const QString & newWorldName );
void loadNewWorld ( const QString & newWorldName, const Tile & newWorldStartingTile, const Tile & newWorldEndingTile );
Tile getStartingTile ( ) const;
void setStartingTile ( const Tile & newStartingTile );
Tile getEndingTile ( ) const;
void setEndingTile ( const Tile & newEndingTile );
std::shared_ptr < Nodifier > getWorldNodifier ( ) const;
void setWorldNodifier ( const std::shared_ptr < Nodifier > & newWorldNodifier );
Tile getTileFromWorld ( int x, int y );
void printNodes ( );
void printWorld ( );
std::list < std::pair <int, int> > generatePath ( );
};
#endif
这是包含Tile定义的共享库的头文件:
#ifndef WORLD_H
#define WORLD_H
#include "world_global.h"
#include <vector>
#include <memory>
#include <QObject>
#include <QImage>
class Tile
{
public:
Tile(int xPosition, int yPosition, float tileWeight);
virtual ~Tile() =default;
float getValue() const {return value;};
void setValue(float newValue) {value = newValue;};
int getXPos() const {return xPos;};
int getYPos() const {return yPos;};
void setXPos(int newPos) {xPos = newPos;};
void setYPos(int newPos) {yPos = newPos;}
bool operator== (const Tile & other) const
{return (getXPos() == other.getXPos()) && (getYPos() == other.getYPos());};
protected:
int xPos;
int yPos;
float value;
};
class Enemy : public Tile
{
public:
Enemy(int xPosition, int yPosition, float strength);
virtual ~Enemy() = default;
bool getDefeated() const {return defeated;}
void setDefeated(bool value) {defeated = value;};
private:
bool defeated; //false by construction
};
class PEnemy: public QObject, public Enemy
{
Q_OBJECT
public:
PEnemy(int xPosition, int yPosition, float strength);
virtual ~PEnemy() = default;
float getPoisonLevel() const;
void setPoisonLevel(float value);
public slots:
bool poison();
signals:
void dead();
void poisonLevelUpdated(int value);
private:
float poisonLevel;
};
class Protagonist: public QObject, public Tile
{
Q_OBJECT
public:
Protagonist();
void setXPos(int newPos) {xPos = newPos; emit posChanged(xPos, yPos);}
void setYPos(int newPos) {yPos = newPos; emit posChanged(xPos, yPos);}
void setPos(int newX, int newY) {if (xPos != newX || yPos != newY) {xPos = newX; yPos = newY; emit posChanged(xPos, yPos);}}
float getHealth() const {return health;};
void setHealth(float value) {health = value;}
float getEnergy() const {return energy;}
void setEnergy(float value) {energy = value;}
signals:
void posChanged(int x, int y);
private:
float health; //100.0f by construction
float energy; //100.0f by construction
};
class WORLDSHARED_EXPORT World
{
public:
World() = default;
//to obtain non-overlapping enemies and healthpacks you should call the following 3 methods in this order
std::vector<std::unique_ptr<Tile>> createWorld(QString filename);
std::vector<std::unique_ptr<Enemy>> getEnemies(unsigned int nrOfEnemies);
std::vector<std::unique_ptr<Tile>> getHealthPacks(unsigned int nrOfPacks);
std::unique_ptr<Protagonist> getProtagonist();
int getRows() const {return rows;};
int getCols() const {return cols;};
private:
int rows, cols;
QImage world;
std::vector<QPoint> used; //only for internal use
};
#endif // WORLD_H
我确定我所做的一切都正确,所以如果有人可以告诉我为什么它无法编译,我会很乐意。
在此先非常感谢,我已经坚持很长时间了。
最好的问候,约书亚
如果我将templahttps://stackoverflow.com/help/how-to-answerte专业化设置移动到定义了Tile类的头文件中(当然,在定义该类之后,但之后再进行任何更改),则代码将编译。
通常,当您自己也实现类时,这无关紧要。 我认为这与在共享库中实现的此类有关。 我不是C ++专家,所以我无法解释这一点。 但是我很想在这里有人继续解释它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.