使用模板参数创建传递给另一个函数的参数列表

Using template parameters to create a list of arguments which are passed to another function

提问人:Thomas 提问时间:10/17/2023 最后编辑:Thomas 更新时间:10/17/2023 访问量:59

问:

我正在创建一个系统,用户可以通过定义数据片段(称为资源)和作用于资源的函数(称为系统)来创建应用程序。我希望用户纯粹提供某种类型的函数指针,并且从该类型中我想推断出需要传递给该函数的资源。

下面是一些上下文代码:

#include <vector>
#include <unordered_map>
#include <memory>

using TypeID = size_t;

class Type
{
public:
    template <class T>
    static TypeID ID()
    {
        static TypeID id = s_Counter++;

        return id;
    }

private:
    inline static TypeID s_Counter = 0;
};

struct Resource
{
   virtual ~Resource() = default;
};

template <typename T>
struct Res : public Resource
{
    inline static const TypeID ID = Type::ID<T>(); // Type::ID<T>() just returns a unique ID for every type
    T Data;
};

class Application
{
private:
    std::unordered_map<TypeID, std::unique_ptr<Resource>> m_Resources;
    std::vector<void(*)()> m_Systems;

public:
    template <typename T>
    void AddResource()
    {
        m_Resources[Res<T>::ID] = std::make_unique<Res<T>>();
    }

    template <typename T>
    T& GetResource()
    {
        return m_Resources[Res<T>::ID]->Data;
    }

    template <typename... Resources>
    void AddSystem(void (*pSystem)(Resources...))
    {
        m_Systems.push_back([pSystem]() {
            pSystem(/*Here, for every parameter in the parameter pack Resources, 
                    I want to call GetResource<>() with the appropriate template parameter*/);
        });
    }
};

struct Foo
{
    int a;
    float b;
};

void system(Foo foo, int num, float val)
{
    /*do stuff with foo, num and val*/
}

int main()
{
    Application app;

    app.AddResource<Foo>();
    app.AddResource<int>();
    app.AddResource<float>();

    app.AddSystem(system);
}

在函数中,我想将模板参数列表(例如)转换为函数调用列表,以便将这些函数的返回值传递到用户定义的函数中。此示例应生成该行。AddSystem<int, float, Foo>GetResource<int>(), GetResource<float>(), GetResource<Foo>()pSystempSystem(GetResource<int>(), GetResource<float>(), GetResource<Foo>());

有没有一种便携式方法可以做到这一点?比如标准库提供的功能?

如果有另一种明显的方法可以达到相同的结果,也请告诉我,这个设计还没有一成不变。

C++ 模板 元编程

评论

1赞 463035818_is_not_an_ai 10/17/2023
什么?什么?请发布一个最小的可重复示例。确保代码中没有分散实际问题注意力的错误m_Systemsm_Resources
0赞 Thomas 10/17/2023
@463035818_is_not_an_ai更新了问题以提供更多上下文。我还准确地添加了我想要生成的代码的样子。
0赞 463035818_is_not_an_ai 10/17/2023
Type::ID<Data>然后就没有意义了。您可以在此处看到更多代码错误 godbolt.org/z/a4jE351deT Data
0赞 Thomas 10/17/2023
@463035818_is_not_an_ai很抱歉......添加了更多内容,并确保 godbolt.org 对代码感到满意。它现在给出的唯一错误是我试图弄清楚的部分。

答:

1赞 463035818_is_not_an_ai 10/17/2023 #1

若要传递到函数指针,可以使用包扩展:Get<Args>...

#include <iostream>
#include <utility>

void foo(int a,float b,double c) {
    std::cout << a << b << c;
}

template <typename T> int get() { return 0; }



template <typename ...Args>
void bar(void(*f)(Args...)) {
    f( get<Args>()...);  // calls f(get<int>(),get<float>(),get<double>())
}

int main() {
    bar(foo);
}

评论

0赞 Thomas 10/17/2023
不知道包扩展可以以这种方式工作。谢谢!