2010-06-15 35 views
1

我有兩個類用於表示一些硬件:一個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; 

其中......代表循環引用。

有誰知道我該如何避免這個循環引用?我對模板很陌生,所以可能會錯過一些非常簡單的東西。

ps。編譯器確切地知道中斷髮生時將運行的代碼是非常重要的,因爲它會進行一些非常有用的優化 - 它能夠內聯回調函數,並將回調函數的代碼字面地插入在ah/w中斷。

回答

1

從而使按鈕與輸入引腳相關的我會改變設計:

class Button 
{ 
    boost::smart_ptr<InputPin> p_input_pin; 
} 

或改變銷類,以便它具有用戶的列表。這可能是更好的設計,因爲它允許許多訂戶在引腳改變其價值時得到通知。您還可以添加一個設置引腳值的方法(setter)。

使用案例1:按下按鈕。
按鈕更改輸入引腳的狀態。
輸入引腳通知用戶事件。

用例2:中斷。
中斷{object}改變輸入引腳的狀態。
輸入引腳通知用戶事件。

訂閱者/發佈者設計模式很適合這些用例。

+0

我可能是錯的,但是對於傳統的主題/觀察者,是不是指向存儲在運行時迭代的表中的觀察者函數?這不幸的是膨脹了我的代碼,迫使我回到C風格的非對象定向編程。 應該可以做到這一點 - 它是確定性的,編譯器知道在中斷髮生時應該運行哪些代碼。但是,我如何獲取它來內聯代碼,而不使用函數指針作爲模板參數? (這導致循環參考)?我可以以不同的方式實例化這些類嗎? – TimYorke34 2010-06-15 20:23:56

0

我認爲這可能是一個過早優化的情況?

爲什麼您認爲您需要將編譯轉換爲直接代碼,而不是在運行時調度?

+0

我正在嘗試編寫一些非常低級別的驅動程序,這些驅動程序將用作我係統中每一個系統的基礎。它可能聽起來很激烈,但是如果中斷處理程序的代碼沒有內聯,編譯器必須在調用處理程序函數(例如,可能只設置一個位)之前保存每個寄存器,然後再重新恢復所有寄存器 - 也許是時間增加10倍?我無法承受這是我所有嵌入式系統的基礎。 – TimYorke34 2010-06-15 20:39:37

+0

爲什麼你買不起?您當前的代碼無效,因此您無法對其進行配置? – 2010-06-16 08:31:35

+0

嗨,我正在使用的處理器只有1K。我知道有些人如果說我用C語言而不是彙編語言會笑,但不介意麪向對象編程! 我設法做了一個使用測試類的概念證明,它不需要在實例化時引用對方(避免使用循環引用),所以我知道如果我可以繞過語法,它就可以工作。 – TimYorke34 2010-06-16 22:07:34

0

也許看Curiously Recurring Template Pattern

如果你從這個

template <int pinNumber> class InputPin 
{ 
    static bool IsHigh() 
    { 
    return ((*portAddress) & (1<<pinNumber)); 
    } 
}; 

template <int Pin> class Button 
{ 
    static bool IsPressed() 
    { 
    return !InputPin<Pin>::IsHigh(); // might need typename here 
    } 
}; 

Button <1> powerButton; 

if (powerButton.IsPressed()) 

也許開始是什麼,那麼它可能進展爲

template <int pinNumber, typename event> class InputPin 
{ 
    static bool IsHigh() 
    { 
    event::OnA(); 
    return ((*portAddress) & (1<<pinNumber)); 
    } 
}; 

template <int Pin> class Button 
{ 
    static bool IsPressed() 
    { 
    return !InputPin<Pin,Button>::IsHigh(); // might need typename here 
    } 

    OnA(){} 
    OnB(){} 
}; 
+0

這看起來很有希望,但我需要靜態多態才能將Button類與任何具有函數「bool IsHigh()」的類一起使用。這個引腳/按鈕的例子是我所有不同的驅動程序類將如何交互的比喻。按鈕並不總是連接到輸入引腳。 例如,Button對象可能需要查看一個比較器輸出,其中物理按鈕連接到比較器的一個輸入端? 如果我將Pin或Comparator類作爲類型名傳遞給Buttton,我是否回到了原點? 我會在明天閱讀鏈接並報告回來。 – TimYorke34 2010-06-15 21:47:27

+0

爲了回到你身邊,我看了一下CRTP,儘管它很有趣,但它似乎並不涉及我的問題。它涉及將自己作爲模板參數傳遞給它們所得到的基類模板的類。除非我錯過了一些東西,否則我認爲這不會解決我的問題。我可能會在別處使用它,所以謝謝! – TimYorke34 2010-06-16 22:13:23

1

在情況下,它會幫助別人,我曾出局方式:

typedef Button< Pin<B7>, &OnButtonChange > TestButton; 

PinIRQ< B7, &TestButton::InputChangedISR > irqPin; 
TestButton testButton; 

Button對象實際上並不需要知道有關PinIRQ中斷的任何信息,所以我可以使用原始(無中斷)Pin類來聲明它,它不需要Button相關的傳遞作爲模板參數。我可以使用這個Button聲明實例化一個完整的PinIRQ類,並且一切都很完美。

我從PIN對象導出PinIRQ爲了讓我「過載」之類的模板給我Pin<int PinNumber>PinIRQ<int PinNumber, void (*ISR)()>

它不是我曾經寫過的代碼的最好的一塊,但它至少起作用。