using an absolute pointer address as a template argument

前端 未结 6 2529
攒了一身酷
攒了一身酷 2021-02-19 22:49

I have a template class which takes as its first template argument a foo * pointer. I\'d like to instantiate one of these with a foo located at an absolute address, like so:

6条回答
  •  终归单人心
    2021-02-19 23:39

    Casting to/from ints works, but as pointed out, it's dangerous. Another solution similar to JimmyB's is to use enum classes instead of function pointers. The enum class member values are set to the device addresses as specified inthe vendor-supplied header. For instance, for the STM32 series, ST provides a header with the following defined:

    // Vendor-supplied device header file (example)
    
    #define GPIOA_BASE = 0x40001000
    #define GPIOB_BASE = 0x40002000
    //    etc...
    

    In your code, create an enum class:

    #include 
    
    enum class GPIO : uint32_t {
        A = GPIOA_BASE, 
        B = GPIOB_BASE, 
        C = GPIOC_BASE, 
        D = GPIOD_BASE, 
        E = GPIOE_BASE,
        F = GPIOF_BASE,
        G = GPIOG_BASE,
        #ifdef GPIOH_BASE   //optional: wrap each member in an #ifdef to improve portability
        H = GPIOH_BASE,
        #endif
        //.. etc
    };
    

    To avoid multiple messy casts, just do it once in the class using a private method. For example then your LedToggle class would be written like this:

    template class LedToggle
    {
        static_assert(PIN < 15, "Only pin numbers 0 - 15 are valid");
    
        volatile auto GPIOPort(GPIOPORT PORT) {
            return reinterpret_cast(port_);
        }
    
        uint32_t mTicks;
        uint32_t mSetReset;
    
        public:
    
        LedToggle()
        {
            mTicks = 0;
            mSetReset = 1 << PIN;
        }
    
        void Update()
        {
            uint32 mask = ((mTicks++ & RATE) - 1) >> 31;
            GPIOPort(PORT)->BSRR = mSetReset & mask;
            mSetReset ^= ((1 << PIN) | (1 << (PIN + 16))) & mask;
        }
    };
    
    LedToggle led;
    

    The benefit of this method is that the class users are forced to use only members of the GPIO enum class, therefore invalid addresses are prohibited.

    You can use enum classes for any of the template parameters, for instance you could replace the PIN parameter with an enum class whose members are set to the vendor's specified GPIO_PIN_1, GPIO_PIN_2, etc. Then you'd write:

    LedToggle 
    

提交回复
热议问题