基于硬件寄存器的非类型模板参数

时间:2013-05-15 21:46:27

标签: c++ templates stm32 non-type

我正在使用STM32的硬件定时器与许多光学编码器连接。我想创建一个模板化的类,它提供了一个方便的接口,用于与硬件计时器进行交互。定时器寄存器是存储器映射的,它们的地址在制造商提供的与器件数据表匹配的头中是#defined。模板参数实际上是计时器外围设备的基本存储器地址。下面是我目前正在尝试做的最小工作示例:

#include <cstdint>

// Effectively supplied by chip manufacturer headers
struct timer_peripheral {
  volatile uint32_t count;
  // ... lots of other registers ...
};
// Also supplied by chip manufacturer headers
#define TIM1 ((timer_peripheral *) 0x40000000)
#define TIM2 ((timer_peripheral *) 0x40000400)
// My templated class
template <timer_peripheral * Timer>
class OpticalEncoderCounter {
  OpticalEncoderCounter();
};

template <timer_peripheral * Timer>
OpticalEncoderCounter<Timer>::OpticalEncoderCounter()
{
}

int main()
{
  // option 1
  OpticalEncoderCounter<TIM1> encoder0;

  // option 2
  timer_peripheral * t = TIM2;
  OpticalEncoderCounter<t> encoder1;
}

然而,当我编译时,我用g ++ - 4.7.2 -std = c ++ 11得到这些错误:

误差|无法将模板参数'1073742848u'转换为'timer_peripheral *'

误差| 't'不是有效的模板参数,因为't'是变量,而不是变量的地址

在阅读了关于非类型模板参数的内容之后,我仍然不确定如何解决我的问题以及模板是否可以像我想的那样使用。我在选项1中尝试了static_cast和reinterpret_cast,但它似乎没有任何区别。

3 个答案:

答案 0 :(得分:1)

短版

模板非类型参数必须是常量表达式。 ((timer_peripheral *) 0x40000000)包含指针类型的reinterpret_cast,因此您不能在常量表达式中使用它。


C ++ 03

[temp.arg.nontype] / 1

  

非类型非模板模板参数的模板参数应为以下之一:

     
      
  • 整数或枚举类型的整数常量表达式;或
  •   
  • [...]
  •   
  • 具有外部链接的对象或函数的地址,包括函数模板和函数   template-ids但不包括非静态类成员,表示为& id-expression,如果名称引用函数或数组,或者相应的template-parameter是引用,则&是可选的;或
  •   
  • [...]
  •   

所以我们必须使用整数常量表达式。

[expr.const] / 1

  

一个整数常量表达式只能包含文字(2.13),枚举数,常量变量或用常量表达式(8.5)初始化的整数或枚举类型的静态数据成员,整数或枚举类型的非类型模板参数,以及sizeof表达式。 [...] 只能使用转换为整数或枚举类型。

((timer_peripheral *) 0x40000000)包含对指针类型的强制转换,因此它不能出现在整数常量表达式中。


C ++ 11

[temp.arg.nontype] / 1

  

非类型非模板模板参数的模板参数应为以下之一:

     
      
  • 表示整数或枚举类型的非类型模板参数,模板参数类型的转换常量表达式(5.19);或
  •   
  • [...]
  •   
  • 一个常量表达式(5.19),用于指定具有静态存储持续时间和外部或内部链接的对象的地址,或具有外部或内部链接的函数,包括函数模板和函数模板ID,但不包括非静态类成员,表示(忽略括号)为& id-expression,但如果名称引用函数或数组,则&可以省略,如果相应的模板参数是引用,则省略#include <cstdint> // Effectively supplied by chip manufacturer headers struct timer_peripheral { volatile uint32_t count; // ... lots of other registers ... }; #define TIM1 ((timer_peripheral *) 0x40000000) #define TIM2 ((timer_peripheral *) 0x40000400) enum TIMS { tim1, tim2 }; template < TIMS tim > inline timer_peripheral* get_timer_address() { static_assert(tim && false, "unknown timer identifier"); return nullptr; } template <> inline timer_peripheral* get_timer_address < tim1 >() { return TIM1; } template <> inline timer_peripheral* get_timer_address < tim2 >() { return TIM2; } // My templated class template < TIMS tim > class OpticalEncoderCounter { static timer_peripheral* get() { return get_timer_address<tim>(); } public: OpticalEncoderCounter(); }; template < TIMS tim > OpticalEncoderCounter<tim>::OpticalEncoderCounter() { } int main() { OpticalEncoderCounter<tim1> encoder0; } ;或
  •   
  • [...]
  •   

我们不能使用“设计地址......”的常量表达式,但是我们可以使用转换后的常量表达式吗?

[expr.const] / 2

  

条件表达式是核心常量表达式,除非它涉及以下[...]

之一      
      
  • [...]
  •   
  • a reinterpret_cast(5.2.10);
  •   
  • [...]
  •   

不。不可能。


解决方法

使用函数模板返回指针。

{{1}}

答案 1 :(得分:0)

模板参数必须是整数类型;我认为编译器将它转换为unsigned int。

你可以通过运行它来完成这项工作,并在模板calss中自己明确地投射它,但我认为你不需要。

除非有某些原因你真的需要这个模板化,否则我只会(1)向结构中添加方法;或(2)创建一个仅包含指向结构的指针的包装类。

答案 2 :(得分:0)

使用指针算法将指针转换为常量:

// My templated class


#define TIM_BASE TIM1

const int TIM1_OFFSET = TIM1 - TIM_BASE;

template <size_t timerOffset>
class OpticalEncoderCounter {
public:
  OpticalEncoderCounter();

  timer_peripheral * getTimer() { return  TIM_BASE + timerOffset;}

};

template <size_t timerOffset>
OpticalEncoderCounter<timerOffset>::OpticalEncoderCounter()
{

}


int main()
{

  OpticalEncoderCounter<TIM1_OFFSET> encoder0;

}