类模板实例化:有什么办法绕过这个循环引用吗?
我有两个类用来表示某些硬件:一个 Button 和一个 InputPin 类,它们表示一个按钮,按下该按钮将更改 IC 输入引脚的值。其中一个简单的例子是:
template <int pinNumber> class InputPin
{
static bool IsHigh()
{
return ( (*portAddress) & (1<<pinNumber) );
}
};
template <typename InputPin> class Button
{
static bool IsPressed()
{
return !InputPin::IsHigh();
}
};
这工作得很好,并且通过使用类模板,下面的条件将像我在汇编中手写的一样紧密地编译(单个指令)。
Button < InputPin<1> > powerButton;
if (powerButton.IsPressed())
........;
然而,我正在扩展它来处理中断,并且遇到了循环引用的问题。
与原来的InputPin相比,新的InputPinIRQ类多了一个静态成员函数,当引脚值改变时,硬件会自动调用该函数。我希望它能够通知 Button 类,以便 Button 类可以通知主应用程序它已被按下/释放。我目前正在通过将指针传递给回调函数来做到这一点。为了让编译器内联回调代码,我认为需要将这些函数指针作为模板参数传递。所以现在,这两个新类都有一个额外的模板参数,它是指向回调函数的指针。不幸的是,这给了我一个循环引用,因为要实例化 ButtonIRQ 类,我现在必须执行如下操作:
ButtonIRQ<InputPinIRQ<1, ButtonIRQ< Inp.... >::OnPinChange>, OnButtonChange> pB;
其中 ...... 代表循环引用。
有谁知道如何避免这种循环引用?我是模板新手,所以可能缺少一些非常简单的东西。
附注重要的是,编译器确切地知道中断发生时将运行哪些代码,因为它然后会进行一些非常有用的优化 - 它能够内联回调函数并在 ah/ 上调用的确切地址处逐字插入回调函数的代码w 中断。
I have two classes that I'm using to represent some hardware: A Button and an InputPin class which represent a button that will change the value of an IC's input pin when it's pressed down. A simple example of them is:
template <int pinNumber> class InputPin
{
static bool IsHigh()
{
return ( (*portAddress) & (1<<pinNumber) );
}
};
template <typename InputPin> class Button
{
static bool IsPressed()
{
return !InputPin::IsHigh();
}
};
This works beautifully and by using class templates, the condition below will compile as tightly as if I'd handwritten it in assembly (a single instruction).
Button < InputPin<1> > powerButton;
if (powerButton.IsPressed())
........;
However, I am extending it to deal with interrupts and have got a problem with circular references.
Compared to the original InputPin, a new InputPinIRQ class has an extra static member function that will be called automatically by the hardware when the pin value changes. I'd like it to be able to notify the Button class of this, so that the Button class can then notify the main application that it has been pressed/released. I am currently doing this by passing pointers to callback functions. In order for the callback code to be inlined by the compiler, I believe that need to pass these function pointers as template parameters. So now, both of the new classes have an extra template parameter that is a pointer to a callback function. Unfortunately this gives me a circular reference because to instantiate a ButtonIRQ class I now have to do something like this:
ButtonIRQ<InputPinIRQ<1, ButtonIRQ< Inp.... >::OnPinChange>, OnButtonChange> pB;
where the ...... represents the circular reference.
Does anyone know how I can avoid this circular reference? I am new to templates, so am probably missing something really simple.
ps. it's important that the compiler knows exactly what code will be run when the interrupt occurs as it then does some very useful optimisation - it is able to inline the callback function and literally inserts the callback function's code at the exact address that is called on a h/w interrupt.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我会更改设计,以便按钮与输入引脚相关联:
或者更改引脚类别,使其具有订阅者列表。这可能是更好的设计,因为它允许在 pin 值更改时通知许多订阅者。您还可以添加一个方法(设置器)来设置引脚的值。
用例 1:按下按钮。
按下按钮会改变输入引脚的状态。
输入引脚通知事件的订阅者。
用例 2:中断。
中断{object}更改输入引脚的状态。
输入引脚通知事件的订阅者。
订阅者/发布者设计模式非常适合这些用例。
I would change the design so that a button is associated with an input pin:
Or change the pin class so that it has a list of subscribers. This may be the better design since it allows many subscribers to be notified when the pin has changed its value. You could also add a method (setter) that sets the pin's value.
Use case 1: Button press.
Button Press changes state of input pin.
Input pin notifies subscribers of event.
Use case 2: Interrupt.
Interrupt {object} changes state of input pin.
Input pin notifies subscribers of event.
The Subscriber / Publisher design pattern suits these use cases well.
如果它对其他人有帮助,我已经解决了这个问题:
Button 对象实际上不需要了解有关 PinIRQ 中断的任何信息,因此我可以使用原始(无中断)Pin 类来声明它,它不需要任何与按钮相关的传递作为模板参数。我可以使用此 Button 声明实例化完整的 PinIRQ 类,并且一切正常。
我从 Pin 对象派生 PinIRQ,以便允许我“重载”类模板以提供
Pin
和PinIRQ
这不是我写过的最好的代码,但它至少可以工作。
In case it will help anyone else, I have worked out a way round this:
The Button object doesn't actually need to know anything about the PinIRQ's interrupt, so I can just declare it using the original (interrupt-less) Pin class, which needs nothing Button related passing as a template parameter. The I can instantiate a full PinIRQ class using this Button declaration and everything works perfectly.
I'm deriving the PinIRQ from the Pin object in order to allow me to "overload" the class template to give me
Pin<int PinNumber>
andPinIRQ<int PinNumber, void (*ISR)()>
Its not the nicest piece of code I've ever written, but it works at least.
我认为这可能是过早优化的情况?
为什么您认为需要将其编译为直接代码,而不是在运行时调度?
I think this might be a case of premature optimisation?
Why do you think you need to have the compile down to straight code, rather than dispatching at runtime?
也许看看奇怪的重复模板模式
如果你从这个开始的话
也许它可能会进展到
Maybe look at the Curiously Recurring Template Pattern
What if you started from this
Perhaps then it might progress to