Как я могу исправить свой заводской шаблон, чтобы устранить эти ошибки компиляции?

Моя цель - создать систему, в которой я могу предоставить строковое имя класса во время выполнения и заставить его возвращать экземпляр этого класса по очереди. В поисках stackoverflow я наткнулся на пример, который, кажется, делает именно то, что я пытаюсь выполнить, хотя в настоящее время я не могу правильно его скомпилировать. Следующее основано на этом коде:

//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");

Логика заключается в том, что производные объекты, то есть Item, будут регистрировать строку и ссылку на функцию, которая возвращает экземпляр самого себя. При вызове createInstance он принимает введенную пользователем строку и использует карту для определения возвращаемого объекта.

К сожалению, этот код не компилируется правильно и выдает следующие ошибки:

Ошибка 1 ошибка C2752: 'std :: tr1 :: _ Remove_reference ‹_Ty›': несколько частичных специализаций соответствуют списку аргументов шаблона

Ошибка 2, ошибка C2528: 'абстрактный декларатор': указатель на ссылку недопустим c: \ program files \ microsoft visual studio 10.0 \ vc \ include \ type_traits 965

Ошибка 3 ошибка C2528: 'тип': указатель на ссылку недопустим c: \ program files \ microsoft visual studio 10.0 \ vc \ include \ type_traits 349

Если кто-то может помочь сгладить эти ошибки, я был бы очень признателен. Или, возможно, я изначально ошибаюсь, поэтому, если кто-то вместо этого считает, что я должен двигаться в совершенно другом направлении, пожалуйста, дайте мне знать.

Заранее спасибо.


person Brandon    schedule 25.11.2010    source источник
comment
Пожалуйста, измените карту имен переменных на что-нибудь другое. Это сбивает с толку при чтении кода.   -  person Manoj R    schedule 25.11.2010


Ответы (2)


Прошло много времени с тех пор, как этот вопрос был опубликован, но поскольку ответа нет, и я тоже здесь наткнулся, я решил, что добавлю его. Я скопировал тот же заводской код, что и вы (из ответа StackOverflow здесь) и возникла та же проблема. Я нашел решение на этот ответ StackOverflow.

Оказывается, в Visual Studio 2010 (которую, как я предполагаю, вы используете) проблема с std::make_pair. Просто используйте вместо этого std::pair<std::string,LevelObject*(*)()>, и все будет хорошо. По крайней мере, это решило ту же проблему для меня.

person daveaglick    schedule 23.09.2011
comment
Спасибо, что разместили это, у меня была та же проблема. Это исправило первую ошибку, теперь я получаю неразрешенный внешний: частный: статический класс std :: map ‹class std :: basic_string‹ char, struct std :: char_traits ‹char›, class std :: allocator ‹char› ›. ... Веревка продолжается. Есть идеи, почему? эти шаблоны меня до бесконечности смущают, особенно ошибки компиляции: S - person Spencer Rose; 24.09.2011
comment
Эта вторая ошибка выглядит так, как будто было бы действительно сложно попытаться диагностировать без полного сообщения, примеров кода и т. Д. Я предлагаю просто пойти дальше и открыть новый вопрос SO по этому поводу. Кто знает, возможно, вы не первый, у кого возникнет такая проблема. - person daveaglick; 26.09.2011
comment
Спасибо за ответ, это была нерешенная внешняя проблема, касающаяся сбора карт на фабрике. Я исправил это, добавив CBaseFactory :: map_type * CBaseFactory :: map = new map_type (); в base.cpp - person Spencer Rose; 27.09.2011
comment
Боюсь (но не уверен), что проблема немного глубже. Похоже, что VC10 не может правильно специализировать std::remove_reference на ссылках на типы функций. Особенно это не соответствует внутренней реализации std::tr1::_Remove_reference по отношению к T&& или T&. Насколько я могу сказать, это происходит, только если T является ссылкой на тип функции. - person Paul Michalik; 12.02.2012

Я добавил пустые тела в конструктор и деструктор класса LevelObject:

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

Затем объявили статическую переменную-член map класса BaeFactory:

BaseFactory::map_type* BaseFactory::map;

и код, скомпилированный без ошибок как в GCC, так и в Visual Studio.

person Vijay Mathew    schedule 25.11.2010
comment
Спасибо за быстрый ответ, но, внося эти корректировки, я все еще не могу его скомпилировать. - person Brandon; 25.11.2010
comment
Я заметил, что без самой последней строки кода, который я опубликовал, все будет нормально компилироваться. Вы уверены, что скопировали эту строку, когда все тестируете? - person Brandon; 25.11.2010