Hans-Georg L. schrieb:
> Warum ?
Weil deine Variablen nicht constinit/constexpr sind und daher eben
Laufzeit-initialisiert werden. Eigentlich müsstest du "constinit"
hinzufügen, aber reinterpret_cast ist in constant expressions nicht
erlaubt.
placement-new bzw construct_at ist eigentlich eh das falsche Werkzeug,
du willst ja keinen Konstruktor auf den Peripherie-Registern aufrufen!
Man muss den Cast auf die Laufzeit verschieben, und im constant
expression Kontext halt nur mit dem Integer hantieren. z.B. so:
1 | #include <cstdint>
|
2 |
|
3 | #include <memory>
|
4 |
|
5 | constexpr std::uintptr_t CONST_GPIOA_BASE = 0x40020000UL;
|
6 |
|
7 | constexpr std::uintptr_t CONST_GPIOB_BASE = 0x40020400UL;
|
8 |
|
9 | struct gpio_type {
|
10 |
|
11 | volatile std::uint32_t moder; // offset: 0x00
|
12 |
|
13 | volatile std::uint32_t otyper; // offset: 0x04
|
14 |
|
15 | volatile std::uint32_t ospeedr; // offset: 0x08
|
16 |
|
17 | volatile std::uint32_t pupdr; // offset: 0x0C
|
18 |
|
19 | volatile std::uint32_t idr; // offset: 0x10
|
20 |
|
21 | volatile std::uint32_t odr; // offset: 0x14
|
22 |
|
23 | volatile std::uint32_t bssr; // offset: 0x18
|
24 |
|
25 | volatile std::uint32_t lckr; // offset: 0x1C
|
26 |
|
27 | volatile std::uint32_t afr[2]; // offset: 0x20/0x24
|
28 |
|
29 | };
|
30 |
|
31 | template <typename PeriphType, std::uintptr_t Addr>
|
32 | struct PeriphWrapper {
|
33 | [[gnu::always_inline]] inline PeriphType& get () const { return *reinterpret_cast<PeriphType*> (Addr); }
|
34 | [[gnu::always_inline]] inline PeriphType* operator -> () const { return &get (); }
|
35 | };
|
36 |
|
37 | static constexpr PeriphWrapper<gpio_type, CONST_GPIOA_BASE> gpio_A;
|
38 | static constexpr PeriphWrapper<gpio_type, CONST_GPIOB_BASE> gpio_B;
|
39 |
|
40 | int main()
|
41 | {
|
42 |
|
43 | gpio_A->moder = 4711;
|
44 | gpio_B->moder = 0x815;
|
45 |
|
46 | }
|
https://gcc.godbolt.org/z/cejd945na
Die Variablen gpio_A und gpio_B sind leere Dummys und belegen keinen
Speicher, erst beim Aufruf des Pfeil-Operators erfolgt der Cast. Also
eben zur Laufzeit, nur durch das Inlinen wird es dann effizient.
Aber ob das jetzt so schön ist...