C++ 测试 lambda 函数
C++ test if lambda function
我正在制作一个挂钩库,它基本上拦截一个函数并使其跳转到拦截函数。
class CHook
{
public:
template<typename S, typename D>
void SetupHook(S Source, D Destionation)
{
pSource = (PBYTE)Source;
pDestination = (PBYTE)Destionation;
}
private:
PBYTE pSource;
PBYTE pDestination;
};
我希望 CHook::SetupHook 接受(对于目标)DWORD(函数地址)、函数指针,两者都可以类型转换为 PBYTE。
我希望 CHook::SetupHook 也能够从 lambda 获取函数指针,但它不能类型转换为 PBYTE,所以我重载了它,因为我知道 lambda 函数是 类 我使用 std::is_class 来识别它们。
template<typename S, typename D>
void SetupHook(S Source, typename std::enable_if<!std::is_class<D>::value, D>::type Destionation)
{
pSource = (PBYTE)Source;
pDestination = (PBYTE)Destionation;
}
template<typename S, typename D>
void SetupHook(S Source, typename std::enable_if<std::is_class<D>::value, D>::type Destionation)
{
pSource = (PBYTE)Source;
pDestination = (PBYTE)to_function_pointer(Destionation);
}
但它会导致这些错误:
error C2783: 'void CHook::SetupHook(S,std::enable_if<std::is_class<D>::value,D>::type)': could not deduce template argument for 'D'
note: see declaration of 'CHook::SetupHook'
当您编写如下代码时:
template <typename S, typename D>
void SetupHook(S Source, typename std::enable_if<!std::is_class<D>::value, D>::type Destionation)
{
// (...)
}
您使 D
成为不可推导的类型模板参数。也就是说,一个类型模板参数列表,<typename S, typename D>
,是否不对应一个函数的参数列表,所以,编译器无法判断它是哪个类型模板参数应该推导代替
typename std::enable_if<!std::is_class<D>::value, D>::type
形式上,嵌套名称说明符引入了 non-deduced context.
解决方案是让编译器将 D
推导为普通参数类型,并将 std::enable_if
放在其他地方,例如:
template <typename S, typename D>
typename std::enable_if<!std::is_class<D>::value>::type SetupHook(S Source, D Destionation)
{
// (...)
}
现在,编译器发现 D
是第二个参数表达式的类型。
有点 hack-y 技巧,但您可以使用 unary+ 将 lambda 转换为函数指针。请注意,如果 lambda 捕获任何变量,则不能将其转换为函数指针。
template<typename S, typename D>
void SetupHook(S Source, D Destionation)
{
pSource = (PBYTE)Source;
// static_cast is required for avoiding Visual Studio bug
pDestination = (PBYTE)+static_cast<void(*)()>(Destionation);
}
...
void some_func() {}
int main() {
auto str = "hello";
auto some_lambda = [](){};
auto some_capturing_lambda = [=]() {
std::cout << str;
};
SetupHook(str, some_func); // Works
SetupHook(str, some_lambda); // Works
SetupHook(str, some_capturing_lambda); // Error in Unary Expression
}
我正在制作一个挂钩库,它基本上拦截一个函数并使其跳转到拦截函数。
class CHook
{
public:
template<typename S, typename D>
void SetupHook(S Source, D Destionation)
{
pSource = (PBYTE)Source;
pDestination = (PBYTE)Destionation;
}
private:
PBYTE pSource;
PBYTE pDestination;
};
我希望 CHook::SetupHook 接受(对于目标)DWORD(函数地址)、函数指针,两者都可以类型转换为 PBYTE。
我希望 CHook::SetupHook 也能够从 lambda 获取函数指针,但它不能类型转换为 PBYTE,所以我重载了它,因为我知道 lambda 函数是 类 我使用 std::is_class 来识别它们。
template<typename S, typename D>
void SetupHook(S Source, typename std::enable_if<!std::is_class<D>::value, D>::type Destionation)
{
pSource = (PBYTE)Source;
pDestination = (PBYTE)Destionation;
}
template<typename S, typename D>
void SetupHook(S Source, typename std::enable_if<std::is_class<D>::value, D>::type Destionation)
{
pSource = (PBYTE)Source;
pDestination = (PBYTE)to_function_pointer(Destionation);
}
但它会导致这些错误:
error C2783: 'void CHook::SetupHook(S,std::enable_if<std::is_class<D>::value,D>::type)': could not deduce template argument for 'D'
note: see declaration of 'CHook::SetupHook'
当您编写如下代码时:
template <typename S, typename D>
void SetupHook(S Source, typename std::enable_if<!std::is_class<D>::value, D>::type Destionation)
{
// (...)
}
您使 D
成为不可推导的类型模板参数。也就是说,一个类型模板参数列表,<typename S, typename D>
,是否不对应一个函数的参数列表,所以,编译器无法判断它是哪个类型模板参数应该推导代替
typename std::enable_if<!std::is_class<D>::value, D>::type
形式上,嵌套名称说明符引入了 non-deduced context.
解决方案是让编译器将 D
推导为普通参数类型,并将 std::enable_if
放在其他地方,例如:
template <typename S, typename D>
typename std::enable_if<!std::is_class<D>::value>::type SetupHook(S Source, D Destionation)
{
// (...)
}
现在,编译器发现 D
是第二个参数表达式的类型。
有点 hack-y 技巧,但您可以使用 unary+ 将 lambda 转换为函数指针。请注意,如果 lambda 捕获任何变量,则不能将其转换为函数指针。
template<typename S, typename D>
void SetupHook(S Source, D Destionation)
{
pSource = (PBYTE)Source;
// static_cast is required for avoiding Visual Studio bug
pDestination = (PBYTE)+static_cast<void(*)()>(Destionation);
}
...
void some_func() {}
int main() {
auto str = "hello";
auto some_lambda = [](){};
auto some_capturing_lambda = [=]() {
std::cout << str;
};
SetupHook(str, some_func); // Works
SetupHook(str, some_lambda); // Works
SetupHook(str, some_capturing_lambda); // Error in Unary Expression
}