如何使用C++编写一个自定义的函数调用模板类

简介

有时候我们拿到了函数的调用地址,但是需要在call之前做一些判断或者预处理,这时我们就需要封装一个自定义的函数call模板。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstdint>

#include <windows.h>

#include <functional>
#include <type_traits>
#include "scopeexit.h"

enum class ECallId
{
    Func1,
    Func2,
};

typedef bool(*func1)(int, int);

class CCaller final
{
public:
    CCaller() = default;
    ~CCaller() = default;

    CCaller (const CCaller &) = default;
    CCaller (CCaller &&) = default;
    CCaller &operator=(const CCaller &) = default;
    CCaller &operator=(CCaller &&) = default;

    template<typename F, class... Args>
    auto callById(ECallId id, Args &&...args)
    {
        InterlockedIncrement(&caller_ref_count_);

        ON_SCOPE_EXIT
        {
            InterlockedDecrement(&caller_ref_count_);
        };
        
        const uintptr_t func_ptr = getFuncAddressById(id);
        if (func_ptr)
        {
            F f = (decltype(f))func_ptr;
            auto task = std::bind(std::forward<F>(f), std::forward<Args>(args)...);
            return task();
        }

        return makeFailedResult<F, Args...>();
    }

private:
    // match return type
    template<typename F, class... Args,
             typename = std::enable_if_t<std::is_same_v<std::invoke_result_t<F, Args...>, int>>>
    static int makeFailedResult()
    {
        return std::invoke_result_t<F, Args...>(0);
    }

    // match return type
    template<typename F, class... Args,
             typename = std::enable_if_t<std::is_same_v<std::invoke_result_t<F, Args...>, bool>>>
    static bool makeFailedResult()
    {
        return std::invoke_result_t<F, Args...>(false);
    }

    uintptr_t getFuncAddressById(ECallId id) const;

    volatile uint32_t caller_ref_count_ = 0;
};

int main(void)
{
    CCaller caller;
    caller.callById<func1>(ECallId::Func1, 1, 2);
    return 0;
}
posted @ 2025-06-28 18:21  倚剑问天  阅读(18)  评论(0)    收藏  举报