c++ 如何编写一个可变参数函数,在编译时将ID转换为变量,并使用这些变量调用另一个函数?

yrwegjxp  于 2022-12-24  发布在  其他
关注(0)|答案(1)|浏览(150)

我有一个从IDMap到变量的函数,如下所示:

enum CID
{
    A, B
};

struct ComponentA{};
struct ComponentB{};

ComponentA ca;
ComponentB cb;

template <uint32_t id>
constexpr auto & componentForId()
{
    if constexpr (id == A)
        return ca;
    if constexpr (id == B)
        return cb;
}

然后我有一个给定的目标函数要调用:

void someFunction(ComponentA&, ComponentB&)
{ ... }

但是我想只使用由componentForId函数转换的数字标识符来间接调用这个函数,我想函数框架应该是这样的:

template <typename ...Args>
void callIndirectly(Args&&... args)
{
    // How to implement this function so that it in effect calls 
    //      someFunction(componentForId<A>(), componentForId<B>());
}

所以我可以这样称呼它:

callIndirectly(A, B);

让它等于

someFunction(componentForId<A>(), componentForId<B>());

我尝试了各种各样的变体,但是我就是不知道如何正确地打包参数以在这种情况下工作。
https://godbolt.org/z/sxdxeojf3
完整示例:

#include <cstdint>

enum CID
{
    A, B
};

struct ComponentA{};
struct ComponentB{};

ComponentA ca;
ComponentB cb;

template <uint32_t id>
constexpr auto & componentForId()
{
    if constexpr (id == A)
        return ca;
    if constexpr (id == B)
        return cb;
}

void someFunction(ComponentA&, ComponentB&)
{}

template <typename ...Args>
void callIndirectly(Args&&... args)
{
    // How to implement this function so that it in effect calls 
    //      someFunction(componentForId<A>(), componentForId<B>());
}

int main() {
    someFunction(ca, cb);
    someFunction(componentForId<A>(), componentForId<B>());

    callIndirectly(A, B);
}
kb5ga3dv

kb5ga3dv1#

你用运行时参数调用callIndirectly(),你只能使用基于switch-case(或if-else if)的委托逐个参数地将其转换为编译时参数,使用类似于cps的结构调用下一个转换器(最终是访问者):

// base case for visitNext
template<CID... PrevArgs>
auto visitNext() {
    someFunction(ComponentForId<PrevArgs>()...);
}

// assuming arg, args... as arguments, PrevArgs... as compile-time arguments
template<CID... PrevArgs, typename... Args>
auto visitNext(CID arg, Args... args) {
    switch(arg) {
    case 'A': return visitNext<PrevArgs..., A>(args...);
    case 'B': return visitNext<PrevArgs..., B>(args...);
    }
}

然而,根据你调用它的方式,你可能不需要所有这些。你可以直接使用模板值参数调用(这是这里的基本情况),或者你可以使用std::integral_constant<>。后者将整型值封装在类型中(即std::integral_constant<CID, A>std::integral_constant<CID, B>是不同的类型),但可以转换为编译时和运行时的值。

相关问题