首页 > 解决方案 > 解释这是如何工作的以及如何转换为 constexpr

问题描述

我读到在宏上使用 constexpr 是最佳实践,所以我想知道为什么会这样?以及如何将其转换为使用 constexpr。

我尝试创建一个带有 5 个参数的模板。像这样-

constexpr auto FUNC(t1 dll, t2 name, t3 callingret, t4 args, t5 address)
{

}
#define FUNCPTR(dll, name, callingret, args, address) \
    __declspec(naked) callingret dll##_##name##args \
    { \
        static DWORD f##dll##_##name = NULL; \
        if(f##dll##_##name == NULL) \
        { \
        __asm { pushad } \
        f##dll##_##name = Offset(address); \
        __asm { popad } \
        } \
        __asm jmp [f##dll##_##name] \
    }

标签: c++macros

解决方案


在 .NET 中,您可以使用 DLLImport 扩展来重命名从 DLL 导入的函数

using namespace System;
using namespace System::Runtime::InteropServices;

typedef void* HWND;
[DllImport("user32", EntryPoint = "MessageBoxA")]
extern "C" int MsgBox(
    HWND hWnd, String* lpText, String* lpCaption, unsigned int uType);

如果你有地址,就像你假设的原始代码一样,你也可以初始化一个函数指针,例如

const auto user32_MessageBox =
  (int(WINAPI *)( HWND, LPCWSTR, LPCWSTR, UINT )) address;

这里的确切类型取决于来自哪里address。例如,如果您从LoadLibrary()and获得指针GetProcAddress(),则该地址是在运行时从系统调用返回的。任何依赖它的东西都不可能constexpr

将地址的类型声明为 aDWORD并使用 inlineasm是完全不可移植的。上面的版本只有在类型address正确的情况下才可移植,但是您使用的获取地址的方法应该确保这一点。

如果没有宏,代码无法轻松完成的一件事是将参数合并到标识符中。但是,这应该不是必需的。(正如 Ben Voight 指出的那样,宏扩展为的函数中的局部变量不需要具有唯一名称。)


推荐阅读