2015-12-02 48 views
-1

我有一個類有兩個函數foo1和foo2,必須按順序調用:foo1,foo2。如何強制按順序調用幾個函數?

如何強制用戶每次調用foo2時調用foo1?

是否有可能在編譯時檢查這個序列?

的背景是這樣的:我正在開發一個日誌系統基於流,就像COUT,CERR,等等:

trace << "This is a log text followed by a number " << 5 << endl; 

我需要的是強制用戶調用ENDL每次他呼叫跟蹤endl必須在另一個電話號碼跟蹤之前被呼叫。

爲什麼?

  • 當用戶調用endl時,日誌系統必須刷新。每條消息都必須儘快刷新。
  • 日誌也同步,以避免消息重疊。所以我鎖定了跟蹤調用中的互斥量,並在endl調用中解鎖了它。

這些都是限制我:

  • 必須儘可能的簡單,就像COUT
  • 我與Visual Studio 2010的工作,這樣我就可以不使用C + +11。
  • 我不能使用boost庫,因爲我在一個實時環境中工作,而我的老闆想要避免它。
  • 我處於實時環境(RTX)中,我們不想動態分配內存。
+5

在調用foo1()和foo2()的接口中沒有隻有foo()的原因是什麼? – Pixelchemist

+2

爲什麼不將'foo1'和'foo2'設爲私有,所以用戶不能手動調用它們,然後添加一個公共函數'foo'來調用它們? – Andrew

+1

你有看「門面」設計模式嗎? –

回答

0

如何強制用戶每次他已經呼籲 foo1時間打電話foo2的?在編譯時可以檢查這個序列嗎?

我喜歡你的問題!

用了10分鐘左右的想法,我相信答案是NO。

我曾經宣稱軟件是'無限'靈活的。我錯了。

在這裏,您已經要求編譯器或代碼閱讀其他貢獻者的思想。我認爲這是不能做到的。

我認爲foo2()可以通過簡單地捕獲調用時間來確認foo1()以前是否在上次小時間度量(微秒?毫秒?)內被調用過。但這並不能保證(中斷處理可能會延遲10毫秒,以太網可能具有挑戰性),而不是你要求的。

期待其他答案!可能他們再次證明我錯了。


(更新)

也許知道發生錯誤遲到總比不知道要好。

考慮爲每個函數添加一個計數器,並在每次調用時遞增。

也許foo2()可以assert()foo1()被調用的次數不止一次?

但是,如果允許用戶在不調用foo1()的情況下調用foo2(),這種工作是否可行?嗯。也許foo2()必須清除兩個計數器?

0

我不太喜歡這個問題,因爲imho應該通過說明背景是什麼來改進(即爲什麼你需要這個?)。然而,我被道格拉斯O. MOENS答案和公正的OP告訴我的緣故啓發什麼是錯的這種做法,我建議這樣的:

class Foo { 
    private: 
     bool foo1Called; 
    public: 
     Foo() : foo1Called(false) {} 
     void foo1(){ 
      assert(!foo1Called && "You have to call foo1();foo2();"); 
      /*...*/ 
      foo1Called = true; 
     } 
     void foo2(){ 
      assert(foo1Called && "You have to call foo1();foo2();"); 
      /*...*/ 
      foo1Called = false; 
     } 
} 

這是可能的,但我仍然會強烈建議您不要這樣做,而是改變界面(如評論中所建議的:提供公開foo,以正確順序調用私人foo1foo2。實際上封裝的目的就是這樣)。 PS:我只是意識到我錯過了這一點,你希望在編譯時檢查。我猜想通過使用一些奇怪的技巧是可能的,但是隨後又出現了問題,爲什麼你需要這個?從一開始就提供正確的界面可以輕鬆解決您的問題。

1

像這樣:

#include <iostream> 

struct foo_caller { 

    template<class OtherStuff> 
    void call_foos(OtherStuff&& other_stuff) 
    { 
     foo1(); 
     other_stuff(); 
     foo2(); 
    } 

private: 
    void foo1() 
    { 
     std::cout << "foo1" << std::endl; 
    } 
    void foo2() 
    { 
     std::cout << "foo2" << std::endl; 
    } 
}; 

int main() 
{ 
    foo_caller bar; 

    bar.call_foos([] { 
     std::cout << "here is some other stuff" << std::endl; 
    }); 

    return 0; 
} 

預期輸出:

foo1 
here is some other stuff 
foo2 
0

閱讀你的編輯我建議其他的解決方案,不要求你的客戶打電話endl後。

與其說

trace << stuff << endl; 

呼叫

Trace() << stuff; 

的區別在於Trace()實際上是一個構造函數調用返回一個對象從std::ostringstream,你可以轉移到繼承。此輸出緩衝區對象調用endl和/或在析構函數中打印它或任何其他內容。 (請注意,我們不一定打印出我們的調試日誌。)

你可能不喜歡的括號,但是這給你一個機會:有了正確的構造函數,你也可以這樣寫:

Trace("The %s is %d!", "foobar", foobar); 

或混合使用:

Trace("The %s is 0x%x", some_string, some_value) << " and then " << some; 

這實際上是我們用於我們的日誌記錄。

+0

太棒了! * Trace()<< stuff; *解決我的問題。我不想要解決方案* Trace(「The%s ....」*因爲sprintf樣式是exaclty我們想要避免的,因爲如果%和參數的數量不一致或者如果類型一個參數是不正確的,然後跟蹤失敗(我們的RTX情況下BSOD,我們不能總是測試那部分代碼,因爲它運行在真正的大型機器上),但我喜歡混合樣式的新可能性! – Teolazza