C++测试lambda是否正常工作

C++ test if lambda function

本文关键字:工作 常工作 测试 lambda 是否 C++      更新时间:2023-10-16

我正在制作一个钩子库,它基本上拦截了一个函数并使其跳转到拦截函数。

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

从形式上讲,嵌套名称说明符引入了非推导上下文。

解决方案是让编译器推断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是第二个参数表达式的类型。

有点像黑客技巧,但您可以使用 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
}