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
}