Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to map a bool to a 3d point struct with std::map?

Tags:

c++

map

How do I use the following struct:

struct point 
{
    int x;
    int y;
    int z;
};

as a key for std::map<point, bool>? How should I define operator< for two points?

like image 705
szx Avatar asked May 24 '11 11:05

szx


People also ask

Can I use the map with of struct?

In maps, most of the data types can be used as a key like int, string, float64, rune, etc. Maps also allow structs to be used as keys.

Can a map have three values C++?

You cannot have three elements. The STL map stores a key-value pair.

Can we have map inside map in C++?

Implementing Multidimensional Map in C++Multidimensional maps are nested maps; that is, they map a key to another map, which itself stores combinations of key values with corresponding mapped values.

How is Map ordered C++?

By default, a Map in C++ is sorted in increasing order based on its key.


2 Answers

Standard library containers like std::map require that your ordering is a "Strict Weak Ordering", so you have to be very careful when designing one.

The typical approach for a 3-ary tuple looks like this:

bool operator<(const point& other) const
{
   if (x != other.x)
       return (x < other.x);

   if (y != other.y)
       return (y < other.y);

   return (z < other.z);
}

It's like a comparator for just x, but with the difference that if the two xs are the same, you fall through to compare ys. If they are the same, then similarly you fall through to the z comparison.

like image 62
Lightness Races in Orbit Avatar answered Oct 08 '22 16:10

Lightness Races in Orbit


Of course, boost::tuple<int,int,int> would make this utterly unnecessary.

Update Adding the all-inclusive have-your-cake-and-eat-it-too no-drawback solution here. IMHO it rocks!

#include <boost/tuple/tuple_comparison.hpp>

struct point 
{
    int x, y, z;
    point(int x, int y, int z) : x(x), y(y), z(z) {}
    bool operator<(const point& rhs) const 
    {
        return boost::tie(x, y, z) < boost::tie(rhs.x, rhs.y, rhs.z);
    }
};

Here is the kicker: it all optimizes away. Compile:

int main()
{
    point a(1,2,3), b(3,2,1);
    bool lt = a<b;
    return lt?0:255;
}

With g++ -O2 yields the following in assembly.

main:
.LFB1132:
        pushl   %ebp
        xorl    %eax, %eax
        movl    %esp, %ebp
        popl    %ebp
        ret
.LFE1132:

The compiler was able to optimize the whole of this program to ... return 0 effectively. That is pretty neat.


Here goes the simple answer:

struct point 
{
    point(int x, int y, int z) 
        : x(x), y(y), z(z) {}
    int x;
    int y;
    int z;
    bool operator<(const point& rhs) const 
    {
        if (x<rhs.x) return true;
        if (x==rhs.x) 
        { 
            if (y<rhs.y) return true;
            if (y==rhs.y) return z<rhs.z;
        }
        return false;
    }
};

Also, I would consider looking for a redefinition of my struct that will allow using std::lexicographical_compare

#include <algorithm>

// ...
bool operator<(const point& rhs) const 
{
    return std::lexicographical_compare(&xyz, &xyz+3, &rhs.xyz, &rhs.xyz+3);
}
like image 23
sehe Avatar answered Oct 08 '22 18:10

sehe