gpt4 book ai didi

c++ - 将 IO 寄存器作为模板参数传递

转载 作者:搜寻专家 更新时间:2023-10-31 00:55:57 26 4
gpt4 key购买 nike

我想使用一个 IO 寄存器(== 静态内存地址)作为模板参数。问题是,寄存器通常被定义为扩展为类似于 (*(volatile uint8_t*)(11 + 0x20)) 的宏,我不知何故无法正确使用我的模板。

我想写这样的代码:

Foo<PORTB> foo;

这样我就可以轻松更改类使用的 IO 寄存器,而无需任何运行时开销(这对微 Controller 至关重要)。我在下面包含了一个完整的示例:

#include <stdint.h>
#include <stdio.h>
#include <utility>

#define PORTB (*(volatile uint8_t*)(11 + 0x20))

template<volatile uint8_t* PortRegister>
class ControllerPtr final
{
public:
static void SetHigh() { *PortRegister |= 0x2; }
};

template<volatile uint8_t& PortRegister>
class ControllerRef final
{
public:
static void SetHigh() { PortRegister |= 0x2; }
};


int main()
{
ControllerPtr<&PORTB> ptr;
ControllerRef<PORTB> ref;

ptr.SetHigh();
ref.SetHigh();

// Both statements should be equal to:
// PORTB |= 0x2;
}

每次我尝试将 &PORTB 传递给 ControllerPtr 时,g++ 都无法编译:

error: (volatile uint8_t*)((long int)(11 + 32)) is not a valid template argument for volatile uint8_t* {aka volatile unsigned char*} because it is not the address of a variable

error: expression *(volatile uint8_t*)((long int)(11 + 32)) has side-effects

尝试将 PORTB 传递给 ControllerRef 中使用的引用类型时,错误有点不同:

error: *(volatile uint8_t*)((long int)(11 + 32)) is not a valid template argument for type volatile uint8_t& {aka volatile unsigned char&} because it is not an object with linkage

我实际上不明白为什么这个错误是一个错误,因为我没有看到将静态地址传递给模板有任何问题。

最佳答案

非类型模板参数必须是常量表达式,并且常量表达式中不能有 reinterpret_cast(除非它未被求值)。

既然您已经指出除了通过 PORTB 之类的宏之外您无法访问数字地址,所以我建议一个解决方法。虽然 PORTB 不能在模板参数中使用,但我们可以合成一个可以在模板参数中使用的唯一类型,如下所示:

struct PORTB_tag {
static volatile uint8_t& value() { return PORTB; }
};
template <class PortTag>
class ControllerRef final {
public:
static void SetHigh() { PortTag::value() |= 0x2; }
};
int main() {
ControllerRef<PORTB_tag> ref;
ref.SetHigh();
}

当您有很多端口时,为了避免重复输入,我们可以使用宏:

#define PORT_TAG(port) port_tag_for_ ## port
#define MAKE_PORT_TAG(port) struct port_tag_for_ ## port { \
static volatile uint8_t& value() { return port; } \
}
template <class PortTag>
class ControllerRef final {
public:
static void SetHigh() { PortTag::value() |= 0x2; }
};
MAKE_PORT_TAG(PORTB);
int main() {
ControllerRef<PORT_TAG(PORTB)> ref;
ref.SetHigh();
}

http://coliru.stacked-crooked.com/a/401c0847d77ec0e0

关于c++ - 将 IO 寄存器作为模板参数传递,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40774632/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com