【问题标题】:How to create a C++ macro to define function that uses argument list that calls another function?如何创建一个 C++ 宏来定义使用调用另一个函数的参数列表的函数?
【发布时间】:2020-03-27 18:36:06
【问题描述】:

尽管标题看起来很奇怪,但我想做的事情相当简单。看看这些定义:

ImportFunc(void, il2cpp_init_utf16, (const Il2CppChar* domain_name));
ImportFunc(void, il2cpp_shutdown, ());
ImportFunc(void, il2cpp_set_config_dir, (const char* config_path));
ImportFunc(void, il2cpp_set_data_dir, (const char* data_path));
ImportFunc(void, il2cpp_set_commandline_arguments, (int argc, const char* const argv[], const char* basedir));
ImportFunc(void, il2cpp_set_commandline_arguments_utf16, (int argc, const Il2CppChar* const argv[], const char* basedir));
ImportFunc(void, il2cpp_set_config_utf16, (const Il2CppChar* executablePath));
ImportFunc(void, il2cpp_set_config, (const char* executablePath));

我有一堆这样的定义,我想“把它们变成一个函数”。我尝试过这样的事情:

#define ImportFunc(t, n, a) \
t n a \
{ \
void* pfunc = (void*)CallSystem(kernel32, GetProcAddress, Globals::GameAssembly, n); \
return SpoofCall<type>((void*)pfunc, args...); \
}

问题是如何解析函数参数并将它们传递给另一个函数。 SpoofCall 函数看起来像这样:

template<typename Ret = void, typename First = void*, typename Second = void*, typename Third = void*, typename Fourth = void*, typename... Stack>
    __forceinline Ret SpoofCall(void* Func, First a1 = First{}, Second a2 = Second{}, Third a3 = Third{}, Fourth a4 = Fourth{}, Stack... args) {

有没有办法做到这一点?我可以定义函数以接受模板,然后使用这些参数调用 SpoofCall,但我希望使用参数定义函数,以便更轻松地使用它们并将它们与 IntelliSense 集成:

编辑:更改了宏中的错字

【问题讨论】:

  • 如果您更改参数宏的格式,boost 有一些工具可以迭代参数列表。照原样,我认为您不能将变量类型与变量名分开。
  • 为什么不把#define改成合适的模板然后使用呢?
  • 不直接调用 GetProcAddress 有什么意义呢?如果你还没有 GetProcAddress 的地址,你很难得到它。
  • 另外,您提供的代码试图混合两个概念,即加载函数和调用它。根据您所提供的内容,这两个项目似乎应该分开,您加载函数(可能根据需要)然后调用它们,您可能会创建一个 LoadAndCall 宏但您的 ImportFunc 宏不应该执行该工作.而且您在 ImportFunc 中有实际上没有提供的标识符、类型和参数。
  • 如果你对这个符号没问题:((int) argc, (const char*) const argv[], (const char*) basedir),那么我有一个相当简单的答案给你。

标签: c++ templates arguments


【解决方案1】:

你可以试试这样的:

#define ImportFunc(_type,_name,...) \
        _type (&x_##_name) (__VA_ARGS__) = *ImportT<_type,## __VA_ARGS__>(#_name)

// Convenience typedef, as spelling template function
// returning template pointer to function
// is *too* error-prone otherwise
template <typename Ret, typename ...Args>
using FuncT = Ret (Args...);

template <typename Ret, typename ...Args>
FuncT<Ret, Args...> *ImportT(char const *name) {
        std::printf("Name: %s\n", name);
        return (FuncT<Ret, Args...> *)dlsym(RTLD_DEFAULT, name); // GetProcAddress on windows
}       

ImportFunc(double, sin, double);
ImportFunc(double, sqrt, double);
ImportFunc(int, fn3, float);

int main() {
        printf("sin(1) = %.3f\n", x_sin(1.0f));
        printf("sqrt(2) = %.3f\n", x_sqrt(2.0f));
}

符号将引用函数而不是函数,但 IntelliSense 应该接受这一点。引用将在程序启动时初始化。允许使用参数名称会带来更多问题,但这应该可以使用更多的函数重载魔法(有关更多信息,请参阅CppReference article)。

编辑:确实更简单,因为像 float (int a, int b) 这样的东西是 C++ 中的有效类型:

#define ImportFunc(_type,_name,...) \
        _type (&x_##_name) (__VA_ARGS__) = *ImportT<_type (__VA_ARGS__)>(#_name)

template <typename Func>
Func *ImportT(char const *name) {
        std::printf("Name: %s\n", name);
        return (Func *)dlsym(RTLD_DEFAULT, name); // GetProcAddress on windows
}       

ImportFunc(double, sin, double t);
ImportFunc(double, sqrt, double x);
ImportFunc(int, fn3, float a, char const * b);

【讨论】:

    猜你喜欢
    • 2020-03-09
    • 2011-02-27
    • 2019-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多