views:

234

answers:

3

I have a map in C++ and I wish to input my class as the value, and a string as the key. When I try to, I get an error 'Scene_Branding' : illegal use of this type as an expression I get an illegal use of this type as an expression, and I can't seem to find out why. Here is some code.

 string CurrentScene = "Scene_Branding";
 map<string, Scene> Scenes;
 Scenes.insert(std::make_pair("Scene_Branding", Scene_Branding));  //<-- Illegal Error parameter 2

and here is Scene Branding header..

#ifndef Scene_Branding_H
#define Scene_Branding_H

#include "Scene.h"
#include <iostream>
#include <string>


class Scene_Branding : Scene
{
public:
 Scene_Branding();
 ~Scene_Branding();
 void Draw();
};

#endif

and here is Scene header..

#ifndef Scene_H
#define Scene_H

#include <iostream>
#include <string>

class Scene
{
public:
 Scene();
 ~Scene();
 virtual void Draw();

};

#endif

and here is there cpp files.

Scene cpp.

#include "Scene.h"

Scene::Scene()
{

}
Scene::~Scene()
{

}
void Scene::Draw(){
 std::cout << "Hey";
}

Scene_Branding cpp

#include "Scene_Branding.h"

Scene_Branding::Scene_Branding()
{

}

Scene_Branding::~Scene_Branding()
{

}

void Scene_Branding::Draw()
{
 std::cout << "Drawing from Scene_branding";
}
+3  A: 

First, don't store objects themselves in the map, store pointers to your objects.

Second, you need to give an instance of Scene_Branding to std::make_pair, not the class itself.

EDIT: Here's how you go about storing pointers:

 string CurrentScene = "Scene_Branding";
 map<string, Scene*> Scenes;
 Scenes.insert(std::make_pair("Scene_Branding", new Scene_Branding()));

But, since you asked this type of question, i recommend you read a good c++ book for further grasping of concepts like pointers.

erelender
Storing objects is fine as long as the object's class is final.
KennyTM
Aha, I tried this, but I was mistakenly placing Scene_Branding .. anyway, thanks.
Fouf
+2  A: 

Try:

Scenes.insert(std::make_pair("Scene_Branding", Scene_Branding()));
Alexander Gessler
Beat me to it!!
rlbond
This works, but the code is not as intended and cout is outputting Hey, and not Drawing from Scene_Branding.. hmm but thanks for the fix.
Fouf
This is because an instance of Scene is stored in the map, not an instance of Scene_Branding. This is called object slicing, briefly it causes you to lose information declared in Scene_Branding. Storing pointers will not cause this issue.
erelender
Fouf
-1 because of slicing bug. I think you didn't see that the OP wants a container of polymorphic objects. :-)
Emile Cormier
+1  A: 

I think you don't want to do that.

  1. there is no runtime type-mapping in C++, you store objects, not types.
  2. you cannot store polymorphic types in STL containers, use boost::ptr_map instead if it is your wish

So, the "new" code:

class Scene
{
public:
  virtual ~Scene();                  // Virtual Destructor, it's a base class
  virtual Scene* clone() const = 0;  // Polymorphic construction
private:
  // whatever you wish
};

class Scene_Branding: public Scene
{
public:
  virtual Scene_Branding* clone() const { return new Scene_Branding(); }
};

And the new way to store those:

const std::string SceneBrandingKey = "Scene_Branding";

typedef boost::ptr_map<std::string, Scene> scenes_type;

scenes_type Scenes;
Scenes.insert(SceneBrandingKey, new Scene_Branding());

And you can use it thusly:

Scenes["Scene_Branding"].process(); // Note: use '.' not '->'

The nice thing about Boost Pointer Container is that it's been meant for polymorphic types, with exception safety and all, and yet mimics the behavior / interface of the STL so that you are not lost :)

Matthieu M.
I think OP is a little newbie to be diving into boost yet.
erelender
I'm not sure, but IMHO instead ofvirtual Scene_Branding* clone() const there should bevirtual Scene* clone() const ;-)
Dominic.wig
It's funny how everybody thinks C++ newbies need to learn to do things the error-prone manual way, before using libraries that make life easier.
Emile Cormier
+1 After the OP learns about the pitfalls of manual memory management, he/she will come to appreciate shared_ptr and ptr_container.
Emile Cormier
Of course, things that make life easier are better but, in order to use high level stuff efficiently, one must understand low level stuff, don't you think? Don't give a lamborghini to a new driver.
erelender
@Dominic: no, it's correct because a `Scene_Branding*` is convertible to a `Scene*` (it's called covariant return). It means that by invoking the `virtual` method you get a `Scene*` but if you explicitly use the `Scene_Branding::clone` then you obtain a `Scene_Branding*` > if you have more type information, you get a more precise type in return :)
Matthieu M.
@erelender: I only partially agree. I am not going to delve into template metaprogramming or preprocessor programming yet, it's too soon for the OP. On the other hand, why should I not show easy-to-use libraries ? I don't understand why people keep on teaching about `char*` manipulations in C++ because `std::string` are more elaborate when you have strings in just about every other language...
Matthieu M.
@Matthieu: I only partially agree also :). When you teach someone how to use std::string, he only learns how to use std::string. On the other hand teaching char* manupilations allows him to apply the concept of pointer manupilation to other types as well. I think learning a language should be about how stuff works under the hood, not how to use stuff. If one learns how stuff works, others will follow.
erelender