c++ 为什么“reinterpret_cast”在模板参数上不能像预期的那样工作?

wkftcu5l  于 2023-06-25  发布在  其他
关注(0)|答案(1)|浏览(209)

我有以下代码示例:

  1. #include <iostream>
  2. typedef struct MyStruct {
  3. int member;
  4. } crake;
  5. #define GPIOA ( 0x40000000)
  6. template <typename T, crake* Ptr>
  7. struct MyTemplate {
  8. void doSomething() {
  9. Ptr->member = 42;
  10. }
  11. };
  12. int main() {
  13. crake* ptr = reinterpret_cast<crake*>(GPIOA);
  14. MyTemplate<MyStruct, reinterpret_cast<crake*>(GPIOA)> instance;
  15. instance.doSomething();
  16. return 0;
  17. }

我用C++20编译了它。有趣的是,我在行上得到了一个错误
MyTemplate<MyStruct, reinterpret_cast<crake*>(GPIOA)> instance;
但不是在前面的一行,我做了同样的事情,即重新解释转换一个整数到一个指针。
确切的错误消息说:

  1. "error: ‘reinterpret_cast’ from integer to pointer
  2. 29 | MyTemplate<MyStruct, reinterpret_cast<crake*>(GPIOA)> instance;"

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

8wigbo56

8wigbo561#

模板参数如下:

  1. MyTemplate<MyStruct, reinterpret_cast<crake*>(GPIOA)>

...必须是常量表达式。reinterpret_cast不能用于常量表达式。在这种情况下,允许它的问题在于,您创建了一个指向一个在编译时不存在的对象的指针,因此template参数在某种程度上没有意义。编译时存在的内存不同于运行时的内存。
但是,您可以将地址作为模板参数传递,并在运行时执行转换:

  1. #include <iostream>
  2. #include <cstddef>
  3. struct crake {
  4. int member;
  5. };
  6. inline constexpr std::uintptr_t GPIOA = 0x40000000;
  7. template <typename T, std::uintptr_t Address>
  8. struct MyTemplate {
  9. static inline crake * const Ptr = reinterpret_cast<crake*>(Address);
  10. void doSomething() {
  11. Ptr->member = 42;
  12. }
  13. };
  14. int main() {
  15. MyTemplate<crake, GPIOA> instance;
  16. instance.doSomething();
  17. return 0;
  18. }

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

  1. main:
  2. mov dword ptr [0x40000000], 42
  3. xor eax, eax
  4. ret

参见live example on Compiler Explorer

展开查看全部

相关问题