0

EDIT: The problem was that I was trying to call a static function in the global scope of my cpp files, which didn't work for some reason:

//Player.cpp
RTTI::instance()->registerClass(...) // ERROR
Player::Player() {}
Player::~Player() {}

To solve the problem I changed my code as follows:

template <class T>
struct RTTIRegister {   
    RTTIRegister<T>(const std::string& name) { 
        RTTI::instance()->registerClass(name, &T::createInstance); 
    } 
};

#define PROTOTYPE_CREATE(CLASS, BASE) \     
    static BASE* createInstance() { return new CLASS(); }

#define PROTOTYPE_REGISTER(NAME, CLASS) \   
    RTTIRegister<CLASS> __rtti__(NAME);

<------------------- END OF EDIT ---------------------->

I am tryting to write a class / macro which will enable me to create instances of classes, whose name I have stored in strings, read from files. I have lots of derived classes of the class GameObject. When I use the code bellow it gives me an error in Visual Studio C++ 2012 Express:

Error   2   IntelliSense: a trailing return type requires the 'auto' type specifier Player.cpp
Error   1   error C2061: syntax error : identifier 'registerClass'  player.cpp

Why am I receiving this error and what can I do to fix it?

Code:

// JSON 
{
    "GameObjects" : [
        {
            "Class" : "Player",
            "Health" : 15
        }
    ]
}

Now when my program reads the file it should create an instance of the class Player. What I currently have is the following:

class RTTI
{
    typedef GameObject* (*createFunc)(void);

    public:
        static RTTI* instance();
        void registerClass(const std::string& className, createFunc instantiate);
        GameObject* createGameObject(const std::string& className);
    private:
        static RTTI* s_instance;
        std::map<std::string, createFunc> s_registeredClases;
};

#define PROTOTYPE_CREATE(CLASS) \
    static CLASS* createInstance() { return new CLASS(); }

#define PROTOTYPE_REGISTER(NAME, CLASS) \
    RTTI::instance()->registerClass(NAME, &CLASS::createInstance);

Now my player class is defined as:

//Player.h
class Player : public GameObject
{
    PROTOTYPE_CREATE(Player)
}

//Player.cpp
PROTOTYPE_REGISTER("Player", Player) /* **THIS IS WHERE IT GIVES ME AN ERROR */
Player::Player() {}
Player::~Player() {}

After a class has been registered I should be able to create instances by saying RTTI::createGameObject("Player");

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
Ivan Dortulov
  • 355
  • 3
  • 13

3 Answers3

0

You have not defined a static instance() member function in class RTTI. But you are accessing it in the macro:

#define PROTOTYPE_REGISTER(NAME, CLASS) \
RTTI::instance()->registerClass(NAME, &CLASS::createInstance);

PROTOTYPE_REGISTER also takes 2 args.

define PROTOTYPE_CREATE(BASE, CLASS) \

static BASE* createInstance() { return new CLASS(); }

in the player class replace your call to PROTOTYPE_CREATE with PROTOTYPE_CREATE(GameObject, Player)

Community
  • 1
  • 1
  • I am sorry about that, I had shortened the code and forgot to add those. Now the code above is correct, yet I still get the error. – Ivan Dortulov Sep 23 '15 at 18:31
  • if you change the PROTOTYPE_CREATE to #define PROTOTYPE_CREATE(BASE, CLASS) \ static BASE* createInstance() { return new CLASS(); } it should work – Shyamal Desai Sep 23 '15 at 19:37
0

One of your hurdles is the return type from the creation function. Most factory patterns return a pointer to a base class object, in other words a single return type.

A factory can be as simple as a bunch of switch statements, to using a lookup table.

The Lookup Table will consist of a key or string in one column and a pointer to a creation function in the second column. Search the key column for the matching string, then use the function pointer (in the same row) to create that instance. Again, same hurdle: The creation functions must have the same signature in the tables (same return type).

Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154
0
try this: Very small difference from your code:

struct GameObject {

};
typedef GameObject* (*createFunc)(void);
class RTTI
{

public:
    static RTTI* instance();
    void registerClass(const std::string& className, createFunc instantiate);
    GameObject* createGameObject(const std::string& className);
private:
    static RTTI* s_instance;
    std::map<std::string, createFunc> s_registeredClases;
};

RTTI* RTTI::s_instance = nullptr;

RTTI* RTTI::instance()
{
    if (!s_instance)
    {
        s_instance = new RTTI();
    }
    return s_instance;
}
void RTTI::registerClass(const std::string& className, createFunc instantiate)
{
    s_registeredClases.insert(std::make_pair (className, instantiate));
}
GameObject* RTTI::createGameObject(const std::string& className)
{
    return nullptr;
}

**#define PROTOTYPE_CREATE(BASE, CLASS) \
    static BASE* createInstance() { return new CLASS(); }**

#define PROTOTYPE_REGISTER(NAME, CLASS) \
    RTTI::instance()->registerClass(NAME, CLASS::createInstance);


//Player.h
class Player : public GameObject
{
public:
    //static GameObject* createInstance() { return new Player(); }
    PROTOTYPE_CREATE(GameObject, Player);
};
//Player.cpp

int _tmain(int argc, _TCHAR* argv[])
{
    PROTOTYPE_REGISTER("Player", Player)
    return 0;
}
  • Is there a way to call PROTOTYPE_REGISTER inside the cpp file, where the Player class is implemented, i.e.: `//Player.cpp PROTOTYPE_REGISTER("Player", Player) Player::Player(){}`? – Ivan Dortulov Sep 24 '15 at 07:10