目前我有一个类似的模板:
template<typename func, typename ret, typename... args> class Entry{
public:
PVOID Address;
ret operator()(args...){
return ((func) this->Address)(args...);
}
};
我正在使用它:
Entry<int(*)(int), int, int> func;
// ^func ^ret ^args
func.Address = (PVOID) 0xDEADC0DE;
func(123); // calls 0xDEADC0DE with '123' as argument
然而,我想知道是否可能只有这个:
Entry<int(*)(int)> func;
// ^only specifying the function's prototype once instead of breaking it down
func(123);
如果我有这样的话,我就不能重载operator()
,因为我无法将函数指针类型拆分为参数和返回类型(这样我就可以编写return_type operator()(args...)
)。
有没有办法实现这个目标?
我使用VS2013 2013年11月CTP
答案 0 :(得分:5)
你可以通过这样的专业化来实现:
// Entry has one template argument
template<typename func> class Entry;
// and if it's a function type, this specialization is used as best fit.
template<typename ret, typename... args> class Entry<ret(args...)>{
public:
PVOID Address;
ret operator()(args... a){
return ((ret(*)(args...)) this->Address)(a...);
}
};
int main() {
Entry<int(int)> foo;
foo.Address = (PVOID) 0xdeadc0de;
func(123);
}
要像在你的例子中一样使用函数指针类型(虽然我更喜欢函数类型语法),写
// here ------v
template<typename ret, typename... args> class Entry<ret(*)(args...)>{
附录:当我外出吃饭时还有一件事发生在我身上:operator()
存在(轻微)问题,可能会或可能不会引起您的关注:您不会遇到转发问题使用通过值或左值引用传递的参数,因为它们只是在传入时传递(因为参数列表与函数指针和operator()
完全相同),但是如果你计划使用rvalue-reference参数,这些参数不会隐式地对它们起作用。出于这个原因,
Entry<int(int&&)> foo;
foo(123);
无法编译。如果您打算将此函数用于带右值引用的函数,operator()
可以像这样修复:
ret operator()(args... a){
// explicit forwarding ----v
return ((ret(*)(args...)) this->Address)(std::forward<args>(a)...);
}
答案 1 :(得分:1)
可以使用@Wintermutes帖子中显示的部分专精 但是,如果没有它,您应该尝试的是:
template <typename func>
class Entry{
public:
PVOID Address;
template <typename... Args>
auto operator()(Args&&... args)
-> decltype( ((func*) Address)(std::forward<Args>(args)...) ) {
return ((func*) Address)(std::forward<Args>(args)...);
}
};
模板参数必须是函数类型。但是,您可以使用函数类型的函数和指针,并在返回表达式中稍作修改:使用func*
,而不是使用typename std::remove_pointer<func>::type*
作为目标类型,即1} p>
template <typename... Args>
auto operator()(Args&&... args)
-> decltype( ((typename std::remove_pointer<func>::type*) Address)(std::forward<Args>(args)...) ) {
return ((typename std::remove_pointer<func>::type*) Address)(std::forward<Args>(args)...);
}
答案 2 :(得分:0)
元编程方法。首先,一些指针特征试图保留调用约定信息:
template<class...>types {using type=types;};
enum class calling_convention {
cdecl,
clrcall,
stdcall,
fastcall,
thiscall,
vectorcall,
};
template<class Sig>
struct signature_properties;
template<class R, class...Args>
struct signature_properties {
using return_type = R;
using argument_types = types<Args...>;
};
template<class FuncPtr>
struct function_properties;
#define CAT_(A,B) A##B
#define CAT(A,B) CAT_(A,B)
#define CALLING_CONVENTION_SUPPORT( CONVENTION ) \
template<class R, class... Args> \
struct function_properties< R(CAT(__, CONVENTION) *)(Args...) >: \
signature_properties<R(Args...)> \
{ \
using type = R(CAT(__, CONVENTION) *)(Args...) \
static const calling_convention convention = calling_convention::CONVENTION; \
static type from_pvoid(void const* pvoid) { \
return static_cast<type>(pvoid); \
} \
}
CALLING_CONVENTION_SUPPORT(cdecl);
CALLING_CONVENTION_SUPPORT(clrcall);
CALLING_CONVENTION_SUPPORT(stdcall);
CALLING_CONVENTION_SUPPORT(fastcall);
CALLING_CONVENTION_SUPPORT(thiscall);
CALLING_CONVENTION_SUPPORT(vectorcall);
#undef CAT
#undef CAT_
#undef CALLING_CONVENTION_SUPPORT
Icky宏。严重的矫枉过正。未经测试。但是你明白了。
接下来,做一个帮助工作:
template<class FuncPtrType, class R, class Args>
struct helper;
template<class FuncPtrType, class R, class... Args>
struct helper<FuncPtrType, R, types<Args...>> {
FuncPtrType ptr;
R operator()(Args...args)const {
return ptr(std::forward<Args>(args)...);
}
helper(FuncPtrType p):ptr(p) {};
helper( helper const& )=default;
helper& operator=( helper const& )=default;
};
帮助者的完美转发也很诱人。
最后,我们使用上面的特征类将工作从Entry
退回到helper
:
template<class FuncPtrType>
struct Entry:helper<
FuncPtrType,
typename signature_properties<FuncPtrType>::return_type,
typename signature_properties<FuncPtrTpye>::arguments
> {
using parent = helper<
FuncPtrType,
typename signature_properties<FuncPtrType>::return_type,
typename signature_properties<FuncPtrTpye>::arguments
>;
Entry(void const* pvoid):parent( static_cast<FuncPtrType>(pvoid) ) {}
};
除了我们在Entry
中包含一个构造函数以获取void const*
并将类型指针转发给helper
。
一个变化是我们从void*
投射到我们的函数类型,我们知道它是函数类型,而不是我们调用的点。