C++ 中带有可变参数签名的函数映射

2024-05-19

From

Martin Reddy 的 C++ API 设计 - 第 3 章(第 3.3.3 节) 可扩展工厂示例)

我发现工厂模式的这种实现非常高效,它允许用户在运行时注册回调函数(本质上是派生类的构造函数),最终可以在创建该类型的对象时调用该回调函数。代码如下所示,摘自教科书 -

文件:rendererfactory.h

class RendererFactory
{
public:
    typedef IRenderer *(*CreateCallback)();
    static void RegisterRenderer(const std::string &type, CreateCallback cb);
    static void UnregisterRenderer(const std::string &type);
    static IRenderer *CreateRenderer(const std::string &type);
private:
    typedef std::map<std::string, CreateCallback> CallbackMap;
    static CallbackMap mRenderers;
};

文件:渲染器工厂.cpp

#include "rendererfactory.h"

// instantiate the static variable in RendererFactory
RendererFactory::CallbackMap RendererFactory::mRenderers;

void RendererFactory::RegisterRenderer(const std::string &type, CreateCallback cb)
{
    mRenderers[type] = cb;
}

void RendererFactory::UnregisterRenderer(const std::string &type)
{
    mRenderers.erase(type);
}

IRenderer *RendererFactory::CreateRenderer(const std::string &type)
{
    CallbackMap::iterator it = mRenderers.find(type);
    if (it != mRenderers.end())
    {
        // call the creation callback to construct this derived type
        return (it->second)();
    }
    return NULL;
}

class UserRenderer : public IRenderer
{
public:
    ~UserRenderer() {}
    static IRenderer *Create() { return new UserRenderer(); }
};

文件:main.cpp

int main(int, char **)
{
    // register a new renderer
    RendererFactory::RegisterRenderer("user", UserRenderer::Create);

    // create an instance of our new renderer
    IRenderer *r = RendererFactory::CreateRenderer("user");

    r->Render();

    delete r;

    return 0;
}

我对这段代码的限制是它假设是派生对象的构造函数,不带任何参数。例如,如果我有一个派生类 -

class UserRendererMultiArgs : public IRenderer
{
public:
    UserRendererMultiArgs(int, int);
    ~UserRendererMultiArgs() {}
    static IRenderer *Create() { 
        return new UserRendererMultiArgs(); //Incorrect : need to call UserRendererMultiArgs(int, int) ??? 
    }
};

我将如何实现在 RendererFactory 类维护的映射中使用变量参数注册回调的相同结果?

我虽然使用了 varargs 但我不知道该怎么做?!


忽略工厂模式并使用问题的标题,那么这可能会满足您的要求:

#include <map>
#include <memory>
#include <string>

struct IRenderer {};

class UserRendererMultiArgs : public IRenderer {
    public:
    UserRendererMultiArgs(int, int) {}
    ~UserRendererMultiArgs() {}
    static IRenderer *Create(int i1, int i2) {
        return new UserRendererMultiArgs(i1, i2);
    }
};

template <class... Args>
struct MapHolder{
    static std::map<std::string, IRenderer *(*)(Args...)> CallbackMap;
};

template <class... Args>
std::map<std::string, IRenderer *(*)(Args...)> MapHolder<Args...>::CallbackMap;

class RendererFactory {
    public:
    template <class... Args>
    static void RegisterRenderer(std::string name, IRenderer *(*Callback)(Args...)) {
        MapHolder<Args...>::CallbackMap[name] = Callback;
    }

    template <class... Args>
    static IRenderer *Create(const std::string &name, Args &&... args) {
        return MapHolder<Args...>::CallbackMap[name](std::forward<Args>(args)...);
    }
};

int main() {
    RendererFactory::RegisterRenderer("user", &UserRendererMultiArgs::Create);
    std::unique_ptr<IRenderer> r{RendererFactory::Create("user", 42, 3)};
}

(演示玩 https://ideone.com/JRkC8M)

在 C++14 中,你有变量模板,不需要它MapHolder,但标记指定了 C++11。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++ 中带有可变参数签名的函数映射 的相关文章

随机推荐