C ++中带有可变参数签名的功能图 [英] A map of functions with variadic signatures in c++

查看:68
本文介绍了C ++中带有可变参数签名的功能图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

来自


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

Martin Reddy's API Design for C++ - Chapter 3 (section 3.3.3 Extensible Factory Example)

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

I found this implementation of Factory pattern to be pretty efficient which allows a user to register callback functions (essentially constructors for the derived classes) at run time, which can eventually be called when creating an object of that type. The code is shown below, as taken from the textbook -

File:rendererfactory.h

File : 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;
};

文件:rendererfactory.cpp

File : rendererfactory.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

File : 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;
}

此代码的局限性在于它假定是派生对象的构造函数,不接受任何论点。例如,如果我有一个派生类-

My limitation with this code is that it assumes are constructors of derived objects, do not take any arguments. For instance if I had a derived class -

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

我将如何实现在由map维护的映射中使用可变参数注册回调的相同结果。 RendererFactory类是什么?

How would I go about achieving the same results of registering callback with variable arguments in the map maintained by the RendererFactory class?

我虽然使用了varargs,但是我不确定该怎么做?!

I have though of using varargs but I am not sure how to do it ?!

推荐答案

忽略工厂模式并使用问题的标题,然后这可能会做您想要的事情:

Ignoring the factory pattern and going with the title of the question then this might do what you want:

#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)};
}

要播放的演示

在C ++ 14中,您可以使用可变模板而不需要 MapHolder ,但标记指定了C ++ 11。

In C++14 you have variable templates to not need that MapHolder, but the tag specified C++11.

这篇关于C ++中带有可变参数签名的功能图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆