有没有办法删除可变参数模板方法的最后一个模板参数?

Lya*_*yar 6 c++ visual-c++ c++11

我正在努力在 C++11 中创建一个简单的反射器,它将实例函数的函数指针存储为:

static std::unordered_map<std::string, std::pair<void(EmptyClass::*)(void), int>>* methods;
template<typename ClassType, typename returnType, typename... Args>
static void RegistFunction(std::string name, returnType(ClassType::* func)(Args... args)) {
    (*methods)[name] = std::make_pair((void(EmptyClass::*)())func, sizeof...(Args));
}

template<typename ReturnType, typename ClassType, typename... Args>
static ReturnType ExecuteFunction(ClassType* object, std::string name, Args... args) {
    if (object == NULL) return;
    ReturnType(ClassType:: * func)(Args...) = (ReturnType(ClassType::*)(Args...))(*methods)[name].first;
    return (object->*func)(std::forward<Args>(args)...);
}
Run Code Online (Sandbox Code Playgroud)

但是当我想调用ExecuteFunction时,参数的数量可能比函数指针实际接受的数量多。所以我需要从参数列表的尾部删除一些参数,但似乎我只能从头部删除。

template<typename ReturnType, typename ClassType, typename Arg, typename... Args>
    static ReturnType ExecuteFunction(ClassType* object, std::string name, Arg arg, Args... args) {
        if (sizeof...(Args) + 1 > (*methods)[name].second) {
            return ExecuteFunction<ReturnType>(std::forward<ClassType*>(object), std::forward<std::string>(name), std::forward<Args>(args)...);
        }
        if (object == NULL) return;
        ReturnType(ClassType:: * func)( Arg, Args...) = (ReturnType(ClassType::*)(Arg, Args...))(*methods)[name].first;
        return (object->*func)(std::forward<Arg>(arg), std::forward<Args>(args)...);
    }
Run Code Online (Sandbox Code Playgroud)

有没有解决方案可以删除可变参数方法模板尾部的参数?

Pas*_* By 1

std::string这是仅依赖于和 的C++11 实现std::unordered_map。一些强制性备注:

  • 如前所述,由于通过提供的参数推断函数类型,这是非常脆弱的。这是 UB 等待发生的事情。
  • method确实不应该是一个指针。
  • 如果您的返回类型不可分配,这将严重破坏。
  • 类指针实际上应该是一个引用。
  • 如果您认为该实现很疯狂,那么是的,确实如此,您应该放弃完全通用的做法。

和朋友的 C++11 实现可以在这里std::index_sequence找到。

看看它的实际效果

template<typename...>
struct typelist {};

template<size_t, typename, typename, typename, typename>
struct call;

template<size_t N, typename R, typename C, typename... Accum, typename Head, typename... Tail>
struct call<N, R, C, typelist<Accum...>, typelist<Head, Tail...>>
    : call<N, R, C, typelist<Accum..., Head>, typelist<Tail...>>
{
};

template<typename R, typename C, typename... Accum, typename Head, typename... Tail>
struct call<sizeof...(Accum), R, C, typelist<Accum...>, typelist<Head, Tail...>>
{
    template<typename... Ts>
    int operator()(Ts&&...)
    {
        return 0;
    }

    template<typename... Ts>
    int operator()(R& ret, void (EmptyClass::* g)(), C& obj, Accum&... args, Ts&&...)
    {
        auto f = (R (C::*)(Accum...))g;
        ret = (obj.*f)(std::move(args)...);
        return 0;
    }
};

template<typename R, typename C, typename... Args, size_t... Is>
R switcher(int i, index_sequence<Is...>, void (EmptyClass::* g)(), C& obj, Args&... args)
{
    R ret{};
    int unused[] = {(i == Is ?
                   call<Is, R, C, typelist<>, typelist<Args..., void>>{}(ret, g, obj, args...)
                   : 0)...};

    (void)unused;
    return ret;
}

template<typename C, typename R, typename... Args>
void reg(std::string name, R (C::* func)(Args... args)) {
    (*methods)[name] = std::make_pair((void (EmptyClass::*)())func, sizeof...(Args));
}

template<typename R, typename C, typename... Args>
R exec(C* obj, std::string name, Args... args) {
    if(obj == nullptr)
        throw "a tantrum";
    
    auto& info = (*methods)[name];
    auto g = info.first;
    size_t i = info.second;
    if(i > sizeof...(Args))
        throw "a fit";

    return switcher<R>(i, make_index_sequence<sizeof...(Args) + 1>{}, g, *obj, args...);
}
Run Code Online (Sandbox Code Playgroud)