我正在努力在 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)...);
}
但是當我想呼叫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)...);
}
是否有任何解決方案可以洗掉可變引數方法模板尾部的引數?
uj5u.com熱心網友回復:
這是一個僅依賴于std::string和的 C 11 實作std::unordered_map。一些強制性的注釋:
- 如前所述,由于通過提供的引數推斷函式型別,這非常脆弱。這是等待發生的UB。
method真的不應該是一個指標。- 如果您的回傳型別不可分配,這將非常糟糕。
- 類指標實際上應該是一個參考。
- 如果您認為實作是瘋狂的,那么是的,確實如此,您應該放棄完全通用。
std::index_sequence可以在這里找到C 11 的實作和朋友。
看到它在行動。
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...);
}
uj5u.com熱心網友回復:
要繼續使用舊方法,您可以在 C 11 之前使用硬編碼限制進行操作:
// No args
template<typename ReturnType, typename ClassType>
static ReturnType ExecuteFunction(ClassType* object, std::string name)
{
switch ((*methods)[name].second) {
case 0: {
if (object == NULL) return {};
auto func = (ReturnType(ClassType::*)())((*methods)[name].first);
return (object->*func)();
}
default: throw std::runtime_error("Wrong argument");
}
}
// One arg
template<typename ReturnType, typename ClassType, typename T1>
static ReturnType ExecuteFunction(ClassType* object, std::string name, T1 arg1)
{
switch ((*methods)[name].second) {
case 0: return ExecuteFunction(object, name);
case 1: {
if (object == NULL) return {};
auto func = (ReturnType(ClassType::*)(T1))((*methods)[name].first);
return (object->*func)(std::forward<T1>(arg1));
}
default: throw std::runtime_error("Wrong argument");
}
}
// Two args
template<typename ReturnType, typename ClassType, typename T1, typename T2>
static ReturnType ExecuteFunction(ClassType* object, std::string name, T1 arg1, T2 arg2)
{
switch ((*methods)[name].second) {
case 0: return ExecuteFunction(object, name);
case 1: return ExecuteFunction(object, name, std::forward<T1>(arg1));
case 2: {
if (object == NULL) return {};
auto func = (ReturnType(ClassType::*)(T1, T2))((*methods)[name].first);
return (object->*func)(std::forward<T1>(arg1), std::forward<T2>(arg2));
}
default: throw std::runtime_error("Wrong argument");
}
}
// .. up to reasonable limit.
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/516305.html
標籤:C c 11视觉-C
上一篇:為什么需要閉包型別的參考成員?
下一篇:使用逗號格式的多個值獲取用戶輸入
