繁体   English   中英

调用模板化成员函数与模板化全局函数以在通用工厂中创建对象

[英]Call templated member function vs. templated global function to create object in generic factory

在网上搜索了Factory模式的不同方法后,我实现了自己的版本,对此感到非常满意。 Register成员函数为模板类型创建一个函数指针,并使用索引作为键将其存储在std :: map中 下面的代码可以轻松编译和运行(Windows 7 64位,带有GCC的Code :: Blocks 10.05)。

#ifndef OBJECT_FACTORY_HPP
#define OBJECT_FACTORY_HPP

#include <map>

namespace internal {
    template<typename BaseType, typename ObjectType>
    BaseType* CreateFunction() {
        return new ObjectType;
    }
}

template<typename BaseType, typename IndexType>
class ObjectFactory {
    public:
        ObjectFactory();

        template<typename ObjectType>
        bool Register(const IndexType& index);

        bool Unregister(const IndexType& index);

        BaseType* Create(const IndexType& index);

    private:
        typedef BaseType* (*creationCallback)();
        typedef std::map<IndexType, creationCallback> Registry;
        Registry registry;

//    private:
//        template<typename ObjectType>
//        BaseType* CreateFunction();
};

template<typename BaseType, typename IndexType>
ObjectFactory<BaseType, IndexType>::ObjectFactory() {
    registry.clear();
}

template<typename BaseType, typename IndexType>
template<typename ObjectType>
bool ObjectFactory<BaseType, IndexType>::Register(const IndexType& index) {
    if (registry.find(index) != registry.end())
        return false;

    registry[index] = &internal::CreateFunction<BaseType, ObjectType>;
    // registry[index] = &CreateFunction<ObjectType>; <-- FAILS!
    return true;
}

template<typename BaseType, typename IndexType>
bool ObjectFactory<BaseType, IndexType>::Unregister(const IndexType& type) {
    if (registry.find(type) == registry.end())
        return false;

    return (registry.erase(type) == 1);
}

template<typename BaseType, typename IndexType>
BaseType* ObjectFactory<BaseType, IndexType>::Create(const IndexType& index) {
    if (registry.find(index) == registry.end())
        return NULL;

    return registry[index]();
}

//template<typename BaseType, typename IndexType>
//template<typename ObjectType>
//BaseType* ObjectFactory<BaseType, IndexType>::CreateFunction() {
//    return new ObjectType();
//}

#endif

我最初的方法是让CreateFunction作为私有成员向用户隐藏(请查看注释部分,请注意非成员函数需要附加的模板参数)。 但是,这失败并显示以下错误消息,所有错误消息都指向我在Register成员函数中存储函数指针的行:

In member function 'bool ObjectFactory<BaseType, IndexType>::Register(const IndexType&) [with ObjectType = Triangle, BaseType = Shape, IndexType = std::basic_string<char, std::char_traits<char>, std::allocator<char> >]':|
instantiated from here
error: no matches converting function 'CreateFunction' to type 'class Shape* (*)()'|
error: candidates are: template<class ObjectType> BaseType* ObjectFactory::CreateFunction() [with ObjectType = ObjectType, BaseType = Shape, IndexType = std::basic_string<char, std::char_traits<char>, std::allocator<char> >]|

我写了一个小的测试客户端进行测试:

#include "ObjectFactory.hpp"
#include <iostream>

class Shape {
    public:
        Shape() {}
        virtual void print() { std::cout << "At heart, I'm a shape"; }
};

class Triangle : public Shape {
    public:
        Triangle() {}
        void print() { Shape::print(); std::cout << ", but I'm truly a triangle" << std::endl; }
};

int main(int argc, char* argv[]) {
    ObjectFactory<Shape, std::string> objectFactory;

    objectFactory.Register<Triangle>("triangle");

    Shape* triangle = objectFactory.Create("triangle");
    triangle->print();

    delete triangle;

    return 0;
}

这有可能吗? 我认为应该是这样,并且我知道我以某种方式调用了错误的成员函数,但是我不知道为什么。 在相关说明中,由于有人可能会提到它,因此我计划使用* boost :: shared_ptr *进行分配,而不是使用普通的new运算符;)也欢迎其他有关实现的建议。

在文件中,我们将名称空间匿名化

// namespace internal {  
   namespace          {
    template<typename BaseType, typename ObjectType> 
    BaseType* CreateFunction() { ... }  
}

现在可以按原始编写的方式调用非静态函数,而无需使用名称空间:

// registry[index] = &internal::CreateFunction<ObjectType>;  
   registry[index] =           &CreateFunction<ObjectType>; 

文件范围的CreateFunction函数对于翻译单元外部的代码不可见,并且仅由ObjectFactoryObjectFactory

这很好地近似了问题中提出的CreateFunctionprivate访问说明CreateFunction (来自ObjectFactory )。

创建函数应为静态成员:

template<typename ObjectType> static BaseType* CreateFunction();

(上面的代码(不含static )在您的示例中已被注释掉)。

现在您的其他注释掉的代码是有效的:

registry[index] = &CreateFunction<ObjectType>;

编辑:清除一些混乱:

这里的问题主要是语法。 模板和private在这里并不重要,因此让我们简化一下情况:

struct ObjectFactory {
    void CreateFunction() {std::cout << "message";}
    void AnotherFunction()
    {
        ... = &CreateFunction; // what's that?
    }
};

如果CreateFunction是非静态成员函数,则语法&CreateFunction不正确; 我想海湾合作委员会只是抱怨。 然而,更糟糕的是,MS Visual Studio尝试通过内部“更正” &ObjectFactory::CreateFunction的语法并尝试使用它来“帮助”您; 但是它失败并显示错误消息(您拥有模板的事实进一步加剧了它们)。

我不确定Visual Studio的部分(我记得几年前在MSVC 6上遇到过此类麻烦; Visual Studio的较新版本没有此问题)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM