0

My goal is to create a system wherein I can provide the string name of an class at run time and have it return an instance of that class in turn. Searching stackoverflow, I came across an example that seems to do exactly what I am trying to accomplish, although I am currently unable to have it compile properly. The following is based on that code:

//LevelObject.h    
#pragma once

#include <map>
#include <string>

class LevelObject
{
    protected:
        int ID;

    public:
        template<class T> static LevelObject* createT(void)
        {
            return new T(0);
        }

        LevelObject(void);
        ~LevelObject(void);
};

struct BaseFactory
{
    typedef std::map<std::string, LevelObject*(*)()> map_type;

    static LevelObject* createInstance(const std::string& s)
    {
        map_type::iterator it = getMap()->find(s);
        if(it == getMap()->end())
        {
            return 0;
        }
        return it->second();
    }

    private:
        static map_type* objectMap;

    protected:
        static map_type* getMap()
        {
            if(!objectMap)
            {
                objectMap= new map_type;
            } 
            return objectMap; 
        }
};

template<class T>
struct DerivedRegister : BaseFactory
{ 
    DerivedRegister(const std::string& s)
    { 
        getMap()->insert(std::make_pair( s, &LevelObject::createT<T> ));
    }
};


//Item.h
#pragma once

#include "LevelObject.h"

class Item :
    public LevelObject
{
    int ID;
    static DerivedRegister<Item> reg;

public:
    Item(int id);
    ~Item(void);
};


//Item.cpp
#include "Item.h"

Item::Item(int id)
{
    ID = id;
}

Item::~Item(void)
{
}

DerivedRegister<Item> Item::reg("item");

The logic is that the derived objects, i.e. Item, will register a string and reference to a function that returns an instance of itself. On calling createInstance, it will take in a user inputted string and use the map to determine the object to return.

Unfortunately, this code is not compiling correctly, and gives me the following errors:

Error 1 error C2752: 'std::tr1::_Remove_reference<_Ty>' : more than one partial specialization matches the template argument list

Error 2 error C2528: 'abstract declarator' : pointer to reference is illegal c:\program files\microsoft visual studio 10.0\vc\include\type_traits 965

Error 3 error C2528: 'type' : pointer to reference is illegal c:\program files\microsoft visual studio 10.0\vc\include\type_traits 349

If someone can help smooth out these errors, I would greatly appreciate it. Or perhaps I am going about this entirely wrong in the first place, so if someone instead feels that I should be going in a different direction entirely please let me know.

Thanks in advance.

Community
  • 1
  • 1
Brandon
  • 1
  • 1

2 Answers2

1

It's been a long time since this question was posted, but since there's no answer and I stumbled here too, I figured I'd add one. I copied the same factory code you did (from the StackOverflow answer here) and had the same problem. I found the solution at this StackOverflow answer.

It turns out Visual Studio 2010 (which I'm assuming you're using) has a problem with std::make_pair. Just use std::pair<std::string,LevelObject*(*)()> instead and you'll be good to go. At least that resolved this exact same problem for me.

Community
  • 1
  • 1
daveaglick
  • 3,600
  • 31
  • 45
  • Thanks for posting this, I had the same problem. That fixed the first error, now I am getting an unresolved external: private: static class std::map,class std::allocator >.... The string goes on. Any ideas why? these templates confuse me to no end, especially the compile errors :S – Spencer Rose Sep 24 '11 at 15:18
  • That second error looks like it would really tough to try and diagnose without the full message, code samples, etc. My suggestion would be to just go ahead and open a new SO question about it. Who knows, you might not be the first one with the same problem. – daveaglick Sep 26 '11 at 13:22
  • Thanks for the reply, it was an unresolved external regarding the map collection in the factory. I fixed it with adding CBaseFactory::map_type* CBaseFactory::map = new map_type(); into the base.cpp – Spencer Rose Sep 27 '11 at 05:58
  • I am afraid (but not sure) that the problem sits a bit deeper. It appears that VC10 cannot correctly specialize `std::remove_reference` on references to function types. Especially it fails to match the internal implementation of `std::tr1::_Remove_reference` with respect to `T&&` or `T&`. As far as I can say this only happens if `T` is a reference to function type. – Paul Michalik Feb 12 '12 at 08:38
0

I added empty bodies to the LevelObject class constructor and destructor:

LevelObject(void) { }
~LevelObject(void) { }

Then declared the static map member variable of the BaeFactory class:

BaseFactory::map_type* BaseFactory::map;

and the code compiled without errors in both GCC and Visual Studio.

Vijay Mathew
  • 26,737
  • 4
  • 62
  • 93
  • Thanks for the prompt response, but in making these adjustments, I'm still unable to get it to compile. – Brandon Nov 25 '10 at 07:06
  • I noticed that without the very last line of the code I posted, everything will compile fine. Are you sure you copied that line over when you test everything? – Brandon Nov 25 '10 at 07:06