Use member of value as key to map

A long time ago on this forum when I was very new to C++, I happened to see Disch/Duoas/someone else with knowledge give an answer to someone using some boost magic, which involved a map where the key was a member of the value. It was something like:

boost::magic_map<ValueClass, &ValueClass::KeyMember>

But I can't find it through googling nor in the boost reference. Does anyone know/remember what I am talking about?

EDIT: This seems really close but I don't think it's the same one I remember:
http://www.cplusplus.com/forum/general/36880/#msg199716
I'd like to know though if the member can change without breaking some contract of the map?
Last edited on
OK, I have completely no idea what I am doing here. Hopefully you can see what I am trying to do, at least:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <iostream>
#include <tuple>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>

struct Position
{
    int x, y;
    friend bool operator==(Position const &a, Position const &b)
    {
        return std::tie(a.x, a.y) == std::tie(b.x, b.y);
    }
    friend bool operator<(Position const &a, Position const &b)
    {
        return std::tie(a.x, a.y) < std::tie(b.x, b.y);
    }
};

struct Object
{
    Position pos;
    virtual ~Object() = default;
};

struct UniquePtrWrapper : std::unique_ptr<Object>
{
    Position &pos;
    UniquePtrWrapper(pointer p)
    : std::unique_ptr<Object>(p)
    , pos(p->pos)
    {
    }
};

using Container_t = boost::multi_index_container
<
    UniquePtrWrapper,
    boost::multi_index::indexed_by
    <
        boost::multi_index::ordered_unique<boost::multi_index::tag<void>>,
        boost::multi_index::member<UniquePtrWrapper, Position &, &UniquePtrWrapper::pos> //error
    >
>;

int main()
{
    Container_t c;
    c.insert({{1, 1}});
    c.insert({{1, 2}});
    c.insert({{2, 1}});
    c.insert({{2, 2}});
}
closed account (o1vk4iN6)
I wouldn't inherit from anything from the standard library, at least I don't think anything in the std library was designed to be inherited. Only the interface is defined, not the implementation so yah ...

I get what you are trying to do but why are you still trying to have the position stored in the Piece ? If the piece modifies it's own position it could intersect with another Piece. It has to have some knowledge of the board to move and if it has the board it doesn't need to store it's own position simply be pointed to which piece it is.
I want to allow pieces to intersect in some cases.
xerzi wrote:
if it has the board it doesn't need to store it's own position simply be pointed to which piece it is.
Could you elaborate? This doesn't make sense to me.
closed account (o1vk4iN6)
Well I think you have the relationship backwards, there shouldn't be many positions to a board, there should instead be a board with one position to one or many pieces.

 
std::unordered_map<Position, std::vector<Piece>> board;


e: well basically put the way you are trying to do, it would be more beneficial to not have a "board". Then to figure out if a piece is at a certain location you would have to go through every Piece to find out. So what you are basically trying to do is find a container that makes that more efficient ?
/e


Could you elaborate?
void Piece::DoTurn(Board&, Position youAreHere);

It will be told where on the board it is, it doesn't need to store it's location.
Last edited on
xerzi wrote:
Well I think you have the relationship backwards, there shouldn't be many positions to a board, there should instead be a board with one position to one or many pieces.
Why?
xerzi wrote:
well basically put the way you are trying to do, it would be more beneficial to not have a "board".
But the board tracks other information than just pieces and their locations.

I've revised my code, it compiles with -fsyntax-only but not when I actually try to generate an executable: (fixed)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <iostream>
#include <tuple>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/identity.hpp>

struct Position
{
    int x, y;
    friend bool operator==(Position const &a, Position const &b)
    {
        return std::tie(a.x, a.y) == std::tie(b.x, b.y);
    }
    friend bool operator<(Position const &a, Position const &b)
    {
        return std::tie(a.x, a.y) < std::tie(b.x, b.y);
    }
    friend std::ostream &operator<<(std::ostream &os, Position const &p)
    {
        return os << "(" << p.x << ", " << p.y << ")" << std::endl;
    }
};

struct Object
{
    Position pos;
    friend bool operator==(Object const &a, Object const &b)
    {
        return a.pos == b.pos;
    }
    friend bool operator<(Object const &a, Object const &b)
    {
        return a.pos < b.pos;
    }
    friend std::ostream &operator<<(std::ostream &os, Object const &o)
    {
        return os << "Object at " << o.pos;
    }
//    virtual ~Object() = default;
};

using Container_t = boost::multi_index_container
<
    Object,
    boost::multi_index::indexed_by
    <
        boost::multi_index::ordered_unique<boost::multi_index::identity<Object>>,
        boost::multi_index::ordered_non_unique<boost::multi_index::member<Object, Position, &Object::pos>>
    >
>;

int main()
{
    Container_t c;
    c.insert({{1, 1}});
    c.insert({{1, 2}});
    c.insert({{2, 1}});
    c.insert({{2, 2}});

    auto const &obj_index = c.get<1>();
    std::copy(std::begin(obj_index), std::end(obj_index), std::ostream_iterator<Object>(std::cout));

    std::cout << std::endl;

    //auto const &pos_index = c.get<2>();
    //std::copy(std::begin(pos_index), std::end(pos_index), std::ostream_iterator<Position>(std::cout));
}
The issue is obviously that Object is a polymorphic type and I want to use std::unique_ptr.
Last edited on
closed account (o1vk4iN6)
But the board tracks other information than just pieces and their locations.


I didn't say you wouldn't have a board class, you would still need a class for a board obviously simply it wouldn't have an array or whatever to specify what goes where like an actual board does as the pieces themselves define where they would go.


1
2
3
4
5
6
7
8
9
10
11
12
class Proxy
{
public:
    Position pos;
    std::unique_ptr<Piece> piece;

    Proxy(std::unique_ptr<Piece> p) : piece(p)
    {
         piece->InitPosition(&pos);
    }

};


Then you could use it in the multi index container but idk still pretty messy.
Last edited on
I'd still like to easily be able to access pieces by their position without iterating every piece and asking it its position. I'm trying to find a way to do that with my edited code above.
closed account (o1vk4iN6)
You are going to have to iterate over every element, without the guarantee that the position hasn't changed between viewings for any container it will have to review and build each time.
OK, so what I'm getting is, Boost is not the answer here. Thanks for talking me through this :)
Topic archived. No new replies allowed.