Failing with maps

Need help guys, I'm still too dumb for this :S
Basically I have this button class, copy/move constructor and operator assignment where added in the vain attempt to make it work with map, so ignore them.

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
enum class BUTTON { INACTIVE, HIGHLIGHTED, PRESSED, RELEASED };


class Button
{
public:
	Button(std::string path);
	Button(Button& rhs);
	Button(Button&& rhs);
	Button& operator=(Button& rhs);

	~Button();

	void setFrame(BUTTON status);
	void setDestRect(int x, int y, int width = 0, int height = 0);
	SDL_Texture* getTexture()const { return texture; }
	SDL_Point getFrameSize()const { return *frameSize; }
	SDL_Rect getSourceRect()const { return *sourceRect; }
	SDL_Rect getDestRect()const { return *destRect; }
private:
	SDL_Point* frameSize;
	SDL_Rect* sourceRect;
	SDL_Rect* destRect;
	SDL_Texture* texture;
};


Then I have this Singleton called IntroState derived from GameState and basically is just the intro menu

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
enum class INTRO_BUTTON { NEW_GAME, OPTIONS, QUIT };

class IntroState : public GameState
{
public:
	IntroState(IntroState&) = delete;
	IntroState(IntroState&&) = delete;
	void operator=(IntroState&) = delete;
	void operator=(IntroState&&) = delete;
	~IntroState();

	//Public Methods
	static IntroState& instance();
	void init()override;
	void update()override;
	void draw()override;

private:
	IntroState();

	std::map<INTRO_BUTTON, Button> buttons;
};


And there you see the treacherous std::map...
The init function is something like this

1
2
3
4
5
6
void IntroState::init()
{
	buttons[INTRO_BUTTON::NEW_GAME] = std::move(Button("assets/temps/newGameButton.png"));
	buttons[INTRO_BUTTON::OPTIONS] = std::move(Button("assets/temps/optionsButton.png"));
	buttons[INTRO_BUTTON::QUIT] = std::move(Button("assets/temps/quitButton.png"));
}


And ignore the move, that was another attempt at trying everything in order to make it work, but with or without it it just returns me a sh*tload of error messages, which just disappear if I comment out those 3 lines above... I have no idea of how I am misusing the map, please guys, help me figure this out x_x

Main error msg is that there are no appropriate constructors for Button::Button
But there is, and this is it:

1
2
3
4
5
6
7
8
9
10
11
12
13
Button::Button(std::string path) :frameSize{new SDL_Point},sourceRect { new SDL_Rect}, destRect{ new SDL_Rect }, texture{ nullptr }
{
	//Load Texture
	texture = TextureManager::instance().load(path);
	
	SDL_QueryTexture(texture, NULL, NULL, &frameSize->x, &frameSize->y);
	
	//Set sizes
	frameSize->x /= 2;
	frameSize->y /= 2;
	sourceRect->w = destRect->w = frameSize->x;
	sourceRect->h = destRect->h = frameSize->y;
}
Last edited on
Oh my god... don't tell me that retarded map is actually just expecting one of these
Button() {};

...need 20 more hands to assist in consecutive facepalm... =_=

But regardless of that, how should I write this
 
buttons[INTRO_BUTTON::NEW_GAME] = std::move(Button("assets/temps/newGameButton.png"));


for it to work bypassing the default constructor? Or map always default construct the Value first no matter what and then copy/move assign?
Last edited on
Have you tried std::map::emplace? Every container has an emplace function that constructs an object using the supplied arguments.

buttons.emplace(INTRO_BUTTON::NEW_GAME, "assets/temps/newGameButton.png");

This only works if they key (INTRO_BUTTON::NEW_GAME, in this case) has not been added to the map, so you need to check the return value to see if the new button was created.

http://www.cplusplus.com/reference/map/map/emplace/
When you do map[key] = value; it is important to realize that this is just a call to the subscript operator followed by a call to the assignment operator.

It's the same as doing:
1
2
auto& obj = map[key];
obj = value;

map[key] returns a reference to the object that the key maps to. If no such mapping exist it will be created and the object is then constructed using the default constructor.

MZH's solution doesn't work for me for some reason. You could try this instead:
 
buttons.emplace(INTRO_BUTTON::NEW_GAME, Button("assets/temps/newGameButton.png"));

This will move the Button object but I don't think that is something you need to worry about because it should be relatively cheap.

If you don't want to move (or copy) the Button object at all I think the only solution is to use std::piecewise_construct to tell std::pair what arguments it should use to construct its two objects.

1
2
3
buttons.emplace(std::piecewise_construct, 
                std::make_tuple(INTRO_BUTTON::NEW_GAME), // arguments for the key constructor (std::string)
                std::make_tuple("assets/temps/newGameButton.png")); // arguments for the mapped value constructor (Button) 
Last edited on
Thanks a lot guys, the emplace call worked perfectly and now my menu properly show buttons -> http://i.imgur.com/erJS7fY.png :D

I kind of whish VS could give you more information, like you could ask it "what constructor type is being called in this code I've wrote?" (without a cout inside every constructor or assignment operator)
Do you always have a button for each INTRO_BUTTON? If so then why not keep it simple and just make this an array?
Do you always have a button for each INTRO_BUTTON? If so then why not keep it simple and just make this an array?


Just for clarity, because then when I'm polling events and dispatching them, in the case I want to send a specific instruction to a specific button, then I have to write
buttons[INTRO_BUTTON::NEW_GAME].setState(BUTTON::PRESSED)
instead of
buttons[0].setState(BUTTON::PRESSED)
which is more vague and would force me to count buttons every time in different types of menu (like the player menu I think)
Last edited on
Topic archived. No new replies allowed.