从函数中扣除 Return / 参数类型
Deduction of Return / Argument types from function
我有回调对象的类型层次结构。经过大量简化后,它看起来有点像这样:
template <typename Return, typename... Args>
struct Callback
{
virtual Return Call(Args...) =0;
void* mCtx;
}; // ctor, virtual dtor omitted
template <class T, typename Return, typename... Args>
struct MemberCallback: Callback<Return, Args...>
{
Return Call(Args... args) override
{
return (static_cast<T*>(mCtx)->*mFn)(args...);
}
Return(T::*mFn)(Args...);
}; // ctor, specialisation for Return = void omitted
template <typename Return, typename... Args>
struct FunctionPtrCallback: Callback<Return, Args...>
{
Return Call(Args... args) override
{
return mFn(args..., mCtx);
}
Return(*mFn)(Args..., void*);
}; // ctor, specialisation for Return = void omitted
以及推断 MemberCallback<>
s 类型的工厂函数:
template <class T, typename Return, typename... Args>
MemberCallback<T, Return, Args...> MakeCallback(T& object, Return(T::*fn)(Args...))
{
return MemberCallback<T, Return, Args...>(&object, fn);
} // overload for const methods omitted
我正在尝试为 FunctionPtrCallback<>
设置类似的工厂函数,但是我一直 运行 出错:
天真的方法 FunctionPtrCallback<Return, Args...> MakeCallback(Return(*fn)(Args..., void*), void*)
在未能从 void (ActualTypeUsed,void *)
(C2784) 中推断出 Return (__cdecl *)(Args...,void *)
的模板参数后,产生了关于未能找到合适的重载 (C2672) 的抱怨。
编辑:显式指定模板参数 - MakeCallback<void, ActualTypeUsed>
将使其编译, 除了 对于仅采用单个 void*
的函数(MakeCallback<void>()
).
(如果我在 MakeCallback
声明中省略 fn
签名中的 void*
参数,它会编译,但会实例化错误的 FunctionPtrCallback
模板 - FunctionPtrCallback<void, ActualTypeUsed, void*>
而不是 FunctionPtrCallback<void, ActualTypeUsed>
.)
然后我尝试使用临时 'function traits' 模板,类似于 中建议的模板:
template <typename T>
struct FnTraits;
template <typename Return, typename... Args>
struct FnTraits<Return(Args...)>
{
FunctionPtrCallback<Return, Args...> MakeCallback(Return(*fn)(Args..., void*), void* data)
{
return FunctionPtrCallback<Return, Args...>(fn, data);
}
};
现在的投诉是关于在我的 FnTraits<decltype(MyCallback)>::MakeCallback(MyCallback, myData)
的嵌套名称说明符中使用不完整的类型。将 MyCallback
的声明放在 FnTraits<>
之前(无论多么不切实际),也无济于事。
1,用简洁的学术术语来说,为什么我的方法是错误的/我对模板推导有什么误解?
2,如果有办法让它工作,从我的回调中自动推导出 Return
和 Args...
,那是什么?
(我知道 std::function<>
;我宁愿避免使用它。)
编辑:godbolt link
不幸的是,它似乎是一个包扩展,其中包不在列表的末尾,例如Return(*)(Args..., void*)
,是一个非推导上下文(参见 #8 here;免责声明:我不是语言律师)。这意味着 Args
无法从您示例中的 FooBaz
类型推导出来。
但是,您可以解决此问题,方法是将参数包推导为 include void*
,然后稍后删除 void*
: https://godbolt.org/z/aTTqbc
// Given Args that doesn't include void*, take the parameter pack
// out of the tuple and put it into the desired FunctionPtrCallback type.
template <typename Return, typename Tuple>
struct MakeCallbackImpl;
template <typename Return, typename... Args>
struct MakeCallbackImpl<Return, std::tuple<Args...>> {
using type = FunctionPtrCallback<Return, Args...>;
};
// Given Args that *does* include void*, remove it using RemoveLast.
// Args can now be deduced because it appears last in Return(*)(Args...).
template <typename Return, typename... Args>
auto MakeCallback(Return(*fn)(Args...), void* data) {
return typename MakeCallbackImpl<Return, typename RemoveLast<Args...>::type>::type(fn, data);
}
和助手 RemoveLast
,受 this forum thread 启发(但使用 std::tuple_cat
作为便利而不是定义自定义连接):
template<typename First, typename... Rest>
struct RemoveLast {
using type = decltype(std::tuple_cat(
std::declval<std::tuple<First>>(),
std::declval<typename RemoveLast<Rest...>::type>()
));
};
template<typename First>
struct RemoveLast<First> {
using type = std::tuple<>;
};
我有回调对象的类型层次结构。经过大量简化后,它看起来有点像这样:
template <typename Return, typename... Args>
struct Callback
{
virtual Return Call(Args...) =0;
void* mCtx;
}; // ctor, virtual dtor omitted
template <class T, typename Return, typename... Args>
struct MemberCallback: Callback<Return, Args...>
{
Return Call(Args... args) override
{
return (static_cast<T*>(mCtx)->*mFn)(args...);
}
Return(T::*mFn)(Args...);
}; // ctor, specialisation for Return = void omitted
template <typename Return, typename... Args>
struct FunctionPtrCallback: Callback<Return, Args...>
{
Return Call(Args... args) override
{
return mFn(args..., mCtx);
}
Return(*mFn)(Args..., void*);
}; // ctor, specialisation for Return = void omitted
以及推断 MemberCallback<>
s 类型的工厂函数:
template <class T, typename Return, typename... Args>
MemberCallback<T, Return, Args...> MakeCallback(T& object, Return(T::*fn)(Args...))
{
return MemberCallback<T, Return, Args...>(&object, fn);
} // overload for const methods omitted
我正在尝试为 FunctionPtrCallback<>
设置类似的工厂函数,但是我一直 运行 出错:
天真的方法 FunctionPtrCallback<Return, Args...> MakeCallback(Return(*fn)(Args..., void*), void*)
在未能从 void (ActualTypeUsed,void *)
(C2784) 中推断出 Return (__cdecl *)(Args...,void *)
的模板参数后,产生了关于未能找到合适的重载 (C2672) 的抱怨。
编辑:显式指定模板参数 - MakeCallback<void, ActualTypeUsed>
将使其编译, 除了 对于仅采用单个 void*
的函数(MakeCallback<void>()
).
(如果我在 MakeCallback
声明中省略 fn
签名中的 void*
参数,它会编译,但会实例化错误的 FunctionPtrCallback
模板 - FunctionPtrCallback<void, ActualTypeUsed, void*>
而不是 FunctionPtrCallback<void, ActualTypeUsed>
.)
然后我尝试使用临时 'function traits' 模板,类似于 中建议的模板:
template <typename T>
struct FnTraits;
template <typename Return, typename... Args>
struct FnTraits<Return(Args...)>
{
FunctionPtrCallback<Return, Args...> MakeCallback(Return(*fn)(Args..., void*), void* data)
{
return FunctionPtrCallback<Return, Args...>(fn, data);
}
};
现在的投诉是关于在我的 FnTraits<decltype(MyCallback)>::MakeCallback(MyCallback, myData)
的嵌套名称说明符中使用不完整的类型。将 MyCallback
的声明放在 FnTraits<>
之前(无论多么不切实际),也无济于事。
1,用简洁的学术术语来说,为什么我的方法是错误的/我对模板推导有什么误解?
2,如果有办法让它工作,从我的回调中自动推导出 Return
和 Args...
,那是什么?
(我知道 std::function<>
;我宁愿避免使用它。)
编辑:godbolt link
不幸的是,它似乎是一个包扩展,其中包不在列表的末尾,例如Return(*)(Args..., void*)
,是一个非推导上下文(参见 #8 here;免责声明:我不是语言律师)。这意味着 Args
无法从您示例中的 FooBaz
类型推导出来。
但是,您可以解决此问题,方法是将参数包推导为 include void*
,然后稍后删除 void*
: https://godbolt.org/z/aTTqbc
// Given Args that doesn't include void*, take the parameter pack
// out of the tuple and put it into the desired FunctionPtrCallback type.
template <typename Return, typename Tuple>
struct MakeCallbackImpl;
template <typename Return, typename... Args>
struct MakeCallbackImpl<Return, std::tuple<Args...>> {
using type = FunctionPtrCallback<Return, Args...>;
};
// Given Args that *does* include void*, remove it using RemoveLast.
// Args can now be deduced because it appears last in Return(*)(Args...).
template <typename Return, typename... Args>
auto MakeCallback(Return(*fn)(Args...), void* data) {
return typename MakeCallbackImpl<Return, typename RemoveLast<Args...>::type>::type(fn, data);
}
和助手 RemoveLast
,受 this forum thread 启发(但使用 std::tuple_cat
作为便利而不是定义自定义连接):
template<typename First, typename... Rest>
struct RemoveLast {
using type = decltype(std::tuple_cat(
std::declval<std::tuple<First>>(),
std::declval<typename RemoveLast<Rest...>::type>()
));
};
template<typename First>
struct RemoveLast<First> {
using type = std::tuple<>;
};