Déclarant foncteurs pour la comparaison?
-
21-09-2019 - |
Question
J'ai vu d'autres personnes, mais des questions ont trouvé aucun qui applique à ce que je suis en train de réaliser ici.
Je suis en train de trier les entités via ma classe EntityManager en utilisant std :: sort et std::vector<Entity *>
/*Entity.h*/
class Entity
{
public:
float x,y;
};
struct compareByX{
bool operator()(const GameEntity &a, const GameEntity &b)
{
return (a.x < b.x);
}
};
/*Class EntityManager that uses Entitiy*/
typedef std::vector<Entity *> ENTITY_VECTOR; //Entity reference vector
class EntityManager: public Entity
{
private:
ENTITY_VECTOR managedEntities;
public:
void sortEntitiesX();
};
void EntityManager::sortEntitiesX()
{
/*perform sorting of the entitiesList by their X value*/
compareByX comparer;
std::sort(entityList.begin(), entityList.end(), comparer);
}
Je reçois une douzaine d'erreurs comme
: error: no match for call to '(compareByX) (GameEntity* const&, GameEntity* const&)'
: note: candidates are: bool compareByX::operator()(const GameEntity&, const GameEntity&)
Je ne suis pas sûr mais ENTITY_VECTOR est std::vector<Entity *>
, et je ne sais pas si cela pourrait être le problème lors de l'utilisation du foncteur compareByX?
Je suis assez nouveau pour C ++, de sorte que toute sorte d'aide est la bienvenue.
La solution
Et un troisième arrive ... Après avoir modifié vous question, encore un sujet ouvert: votre comparateur prend un const &
à la classe GameEntity
. Il devrait, afin de travailler avec les valeurs de la vector<GameEntity*>
, prendre des arguments de const GameEntity*
à la place.
Autres conseils
A foncteur est une classe qui définit l'opérateur () pour un objet de cette classe peut être « Appelé » avec la même syntaxe que l'appel d'une fonction:
struct functor {
bool operator()(Entity const &a, Entity const &b) {
return a.x < b.x;
}
};
Si vous voulez qu'en tant que membre de votre classe d'entité, vous utiliseriez une classe imbriquée:
class Entity {
float x;
public:
friend class byX;
class byX {
bool operator()(Entity const &a, Entity const &b) {
return a.x < b.x;
}
};
};
Alors, votre genre ressemblerait à quelque chose comme ceci:
std::sort(ManagedEndities.begin(), ManagedEntities.end(), Entity::byX());
Par ailleurs, si vous triez habituellement par les entités X, vous pouvez définir l'opérateur Dans ce cas, votre utilisation de tri serait un peu plus simple: Création de la fonction de comparaison en fonction de membre normal de la classe entité, cependant, conduira à une invocation de tri qui est assez laid - ça va généralement besoin de quelque chose comme std :: mem_fun_ref pour faire le travail; il est assez laid que j'évite généralement pour le code réel. class Entity {
float x;
public:
bool operator<(Entity const &other) {
return x < other.x;
}
};
std::sort(ManagedEntities.begin(), ManagedEntities.end());
Je l'ai vu cette question, récemment, bien ....
La réponse était quelque chose de la manière de: la fonction fournie à sort
ne doit pas être membre fonction de quelque chose. Signification: il doit être une fonction statique, ou une fonction libre. Si vous déclarez une fonction statique, vous devriez toujours précéder par Entity::compareByX
afin de le nommer correctement.
Si vous définissez l'ordre dans la classe elle-même, vous pouvez, comme aJ déjà dit, utilisez un adaptateur de fonction mem_fun
ou mem_fun_ref
de le verser dans un objet foncteur « libre ».
Si vous voulez un objet Entity
faire la comparaison, vous devez fournir sort
avec un objet (appelé foncteur ou comparateur dans ce cas):
struct EntityComp {
bool operator()( const GameEntity& a, const GameEntity& b ) const {
return a.x < b.x;
}
}
...
std::sort( v.begin(), v.end(), EntityComp() );
A la lumière de « ce que vous essayez d'atteindre », je faire une autre supposition ... Vous voulez être en mesure de préciser si vous souhaitez comparer vos objets par leur membre de GameEntity::x
, ou par un membre de leur GameEntity::y
.
La façon la plus simple serait, comme vous l'avez fait, spécifiez un foncteur pour chaque membre:
struct CompareX {
bool operator()( const GameEntity& a, const GameEntity& b ) const {
return a.x < b.x;
}
};
struct CompareY {
bool operator()( const GameEntity& a, const GameEntity& b ) const {
return a.y < b.y;
}
};
CompareX compx; // create a compare object
std::sort( v.begin(), v.end(), compx );
Le « flexible » façon encore plus lourde serait de créer un foncteur modèle:
#include <iostream>
using namespace std;
// a mockup of your class
struct GameEntity { float x, y, z; };
// just to be able to print it...
ostream& operator<<( ostream& o, const GameEntity& g ) {
return o << "(" << g.x << ", " << g.y << ", " << g.z << ")";
}
// cumbersome starts here...
typedef float (GameEntity::*membervar);
// a 'generic' float-member comparator
template< membervar m > struct CompareBy {
bool operator()( const GameEntity& a, const GameEntity& b ) const {
return a.*m < b.*m ;
}
};
// example code
int main() {
using namespace std;
GameEntity v[] = { {1,0,0}, {2,0,1}, {3,-1,2} };
GameEntity* vend = v + sizeof(v)/sizeof(v[0]);
sort( v, vend, CompareBy< &GameEntity::x >() );
copy( v, vend, ostream_iterator<GameEntity>( cout, "\n" ) );
}
essayer ..
class CompareByX
{
operator ()(const GameEntity &a, const GameEntity &b) { ... };
};
...
std::sort( this->begin(), this->end(), CompareByX);
En un mot, un foncteur est un objet de fonction - la STL recherche spécifiquement un opérateur () qui prend les deux paramètres que je l'ai spécifié. Si vous êtes nouveau C ++, je vous suggère de consulter les opérateurs et foncteurs - ils sont très pratique, même en dehors STL
.Edit: la réponse de Jerry est meilleure et plus complète
.