为什么“reinterpret_cast”在模板参数上不能按预期工作?

Ben*_*aef 3 c++ templates reinterpret-cast non-type

我有以下代码示例:

\n
#include <iostream>\n\ntypedef struct MyStruct {\n    int member;\n} crake;\n\n#define GPIOA               ( 0x40000000)\n\ntemplate <typename T, crake* Ptr>\nstruct MyTemplate {\n    void doSomething() {\n        Ptr->member = 42;\n    }\n};\n\n\nint main() {\n    crake* ptr = reinterpret_cast<crake*>(GPIOA);\n    MyTemplate<MyStruct, reinterpret_cast<crake*>(GPIOA)> instance;\n    instance.doSomething();\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

我用 C++20 编译了它。有趣的是我得到了一个错误

\n

MyTemplate<MyStruct, reinterpret_cast<crake*>(GPIOA)> instance;

\n

但不是在之前的行中,我做了同样的事情,即重新解释将整数转换为指针。

\n

确切的错误消息是:

\n
"error: \xe2\x80\x98reinterpret_cast\xe2\x80\x99 from integer to pointer\n   29 |     MyTemplate<MyStruct, reinterpret_cast<crake*>(GPIOA)> instance;"\n
Run Code Online (Sandbox Code Playgroud)\n

我的目标是获取定义为常量值(带有#define)的结构体的地址作为非类型模板参数。我知道这会崩溃,但实际上,地址后面有一个外设,写入它是可以的。所以我认为,我需要使用 const 变量,但我想避免这种情况。

\n

Jan*_*tke 8

模板参数如下:

MyTemplate<MyStruct, reinterpret_cast<crake*>(GPIOA)>
Run Code Online (Sandbox Code Playgroud)

...必须是常量表达式。reinterpret_cast不能在常量表达式中使用。在这种情况下,允许它的问题是您正在创建一个指向编译时不存在的对象的指针,因此模板参数有些毫无意义。编译时存在的内存与运行时存在的内存不同。

但是,您可以将地址作为模板参数传递,并在运行时执行转换:

#include <iostream>
#include <cstddef>

struct crake {
    int member;
};

inline constexpr std::uintptr_t GPIOA = 0x40000000;

template <typename T, std::uintptr_t Address>
struct MyTemplate {
    static inline crake * const Ptr = reinterpret_cast<crake*>(Address);
    void doSomething() {
        Ptr->member = 42;
    }
};


int main() {
    MyTemplate<crake, GPIOA> instance;
    instance.doSomething();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

与原始代码相比,这没有额外的开销,并且编译为:

main:
   mov dword ptr [0x40000000], 42
   xor eax, eax
   ret
Run Code Online (Sandbox Code Playgroud)

请参阅Compiler Explorer 上的实时示例