Невозможно использовать stl-карту со структурой?

struct Node
{
 int a;
 int b;
};

Node node;
node.a = 2;
node.b = 3;

map<int, int> aa;
aa[1]=1; //O.K.

map<Node, int> bb;
bb[node]=1; //Compile Error

Когда я попытался отобразить структуру в int, это дало мне ошибку компиляции. Зачем? Спасибо!

Ответы

Ответ 1

Для того, чтобы быть полезной в качестве ключа на карте, вы должны иметь возможность сравнить ее с помощью operator<(). Вам нужно добавить такой оператор в класс node:

struct Node
{
 int a;
 int b;

 bool operator<( const Node & n ) const {
   return this->a < n.a;   // for example
 }
};

Конечно, что действительный оператор действительно зависит от того, какое сравнение фактически означает для вашей структуры.

Ответ 2

Вы должны указать std:: map, как сравнить объекты Node. По умолчанию он пытается сделать это, используя меньше оператора. Но для Node вы не указали меньше оператора. Самое простое решение - предоставить его.

Пример бесплатной функции:

bool operator<(Node const& n1, Node const& n2)
{
    return n1.a<n2.a || (n1.a==n2.a && n1.b<n2.b);
}

Заметим, что для любой пары объектов Node x, y с !(x<y) и !(y<x) карта будет считать x и y равными (тот же ключ).

Ответ 3

Вам нужно определить меньше оператора, чтобы включить сравнения для вашего типа Node:

struct Node
{
 int a;
 int b;
};

bool operator<(Node const& n1, Node const& n2)
{  
   // TODO: Specify condition as you need
   return ... ;
}

Здесь вы можете проверить, что LessThan Comparable означает для пользовательского типа.

Альтернативное решение - определить функтор, основанный на std:: binary_function. С точки зрения дизайна эта опция имеет преимущества, потому что сравнение эффективно отделено от класса Node. Это позволяет определять карты, специализированные с различными условиями сравнения (функторы).

#include <map>

struct Node
{
 int a;
 int b;
};

struct NodeLessThan
    : public std::binary_function<Node, Node, bool>
{
    bool operator() (Node const& n1, Node const& n2) const
    {
        // TODO: your condition
        return n1.a < n2.a;
    }
};

int main()
{
    Node node;
    node.a = 2;
    node.b = 3;

    typedef std::map<Node, int, NodeLessThan> node_map_t;
    node_map_t bb;
    bb[node] = 1;
}

Таким образом, вы можете определить больше сравнений, чем просто NodeLessThan, например, используя разные условия или сравнивая только Node::a другое сравнение обоих компонентов, Node::a и Node::b. Затем определяются различные типы карт:

typedef std::map<Node, int, NodeLessThan>    node_map_t;
typedef std::map<Node, int, NodeLessThanByA> node_map_a_t;

Такая развязка менее навязчива (вообще не касается класса Node) и выгодна для достижения более расширяемого решения.

Ответ 4

Если вам действительно не нужно сортировать данные по ключу, вы можете использовать новый unordered_map:

#include <unordered_map>

... 

std::tr1::unordered_map<Node, int> aa;  // Doesn't require operator<(Node, Node)

Вам понадобится недавний компилятор для этого.

UPDATE Как указывает Нил, вам нужна специализированная хеш-функция, если вы хотите использовать unordered_map с Node.

struct NodeHash : std::unary_function<Node, size_t>
{ 
    size_t operator()(Node const & node) const
    {
        return static_cast<size_t>(node.a + 1) * static_cast<size_t>(node.b + 1);
    }
};

И тогда карта станет:

 std::tr1::unordered_map<Node, int, NodeHash> aa;

Кроме того, как говорит sellibitze, для сравнения ключей в случае хэш-столкновения необходим оператор ==:

bool operator==(const Node & lhs, const Node & rhs)
{
    return lhs.a == rhs.a && rhs.b == rhs.b;
}

Итак, я думаю, что std:: map намного проще использовать.

Ответ 5

Не могли бы вы отправить сообщение об ошибке компилятора. Они предназначены для того, чтобы сказать вам, что не так.

Я предполагаю, что ваша ошибка возникает, поскольку Node не реализует оператор сравнения, который требуется для карты, чтобы идентифицировать его.