2011-03-04 117 views
6

編輯:動機typedef'ing函數*簽名*(不是指針),以便它可以重用?

假設我定義一個Handler類爲

class Handler { 
public: 
    class Message { /*...*/ }; 
    typedef int (*Callback)(Message *msg); 
    void registerCallback(int msgclass, Callback f); 
}; 

客戶端可以做

int f1(Handler::Message *msg) 
{ /* handle message */ } 

int f2(Handler::Message *msg) 
{ /* handle message */ } 

int main(){ 
    Handler h; 
    h.registerCallback(1, f1); 
    h.registerCallback(2, f2); 
    // .... 
} 

編譯器的確會檢查f1f2是適當的參數registerCallback,但是,客戶需要定義f1f2正確LY。因爲我已經準備好了,所以我希望客戶端能夠使用它。

編輯完

我想要做這樣的事情:

typedef int arithmetic(int i, int j); 

arithmetic sum 
{ 
return i+j; 
} 

arithmetic max 
{ 
    return (i>j)? i:j; 
} 
// etc. 

然而,無論

arithmetic sum 
arithmetic sum() 

不進行編譯,而且這種

arithmetic sum(int i, int j) 

賦予的

func.cpp:4: error: ‘sum’ declared as function returning a function

我想這個原因編譯器錯誤是,我想有一個Handler類將爲它接受一個回調函數,包括參數列表提供typedef

+0

我看不到你想如何傳遞參數到你的算術。在你的例子中,我和j是什麼。 – mkaes 2011-03-04 14:56:08

+0

您可以使用Boost或C++ 0x的功能嗎? – luke 2011-03-04 14:57:57

+0

@ mkaes:對,這是一個錯字,已更正。 – davka 2011-03-04 14:59:56

回答

9

首先,您沒有鍵入一個簽名。簽名是標識單個功能的所有內容。它包含函數的名稱空間/類等等。

你typedef'ed是一個函數的類型。就像你在typedef int inttype哪種類型定義了int的類型那樣,你鍵入了一個函數的類型。

您可以使用typedef-name僅聲明函數。

arithmetic max; // valid 

但它不能用來定義函數。爲了定義函數,您需要逐字和手動提供參數列表。原因包括爲參數提供名稱(可能還有其他更多的技術原因,C++ 0x引入了arithmetic max {};,這會得到特定的初始化含義)。

+0

謝謝,現在問題更加清楚了。其實,我的問題歸結爲提供一種「默認」參數名稱。這似乎是一個很好的功能(見OP中添加了「MOTIVATION」)。你能解釋一下你提到的C++ 0x添加 - 它是如何使用的? – davka 2011-03-04 16:35:26

+0

@davka't t {}'初始化't'。因此,例如'int a {};'value將'a'初始化爲零。這是C++ 0x接受的統一初始化提議。 – 2011-03-04 16:36:49

+0

謝謝,例如我可以編寫'arithmetic max {min};'將'max'定義爲指向函數'min'的變量?順便說一句,我認爲這是數組和結構初始化擴展,所以它應該是'算術最大= {分};是嗎? – davka 2011-03-04 16:55:58

2

因爲,如你所說,你可以使用C++ 0x中,您可以選擇通過typedef'ing一個function做這樣的事情:

編輯,加入你的包含處理程序類的概念回調的typedef:

#include <functional> 
#include <list> 

int max(int a, int b) 
{ 
    return (a>=b) ? a : b; 
} 

class Handler 
{ 
    public: 

     //typedef int (*Callback)(int, int); 
     typedef std::function<int (int, int)> Callback; 

     void add(Callback func) { functions_.push_back(func); } 

    private: 

     std::list<Callback> functions_; 
}; 

int main(int argc, char* argv[]) 
{ 
    Handler handler; 

    handler.add([](int a, int b) -> int { return (a>=b) ? a : b; }); 
    handler.add(max); 

    return 0; 
} 

這是不是你要找的確切語法,但正如其他人所指出的那樣,這是不可能直接使用的typedef的函數簽名。

+0

謝謝,這很有趣。儘管如此,不允許我像我想要的那樣方便用戶使用。我想唯一的是訴諸舊的好(或壞)C宏... – davka 2011-03-04 16:45:18

3

想想你的帖子我會給你一個關於你想要存檔的東西。 你可以嘗試使用boost或C++ 0x lambda。我會繼續提升。

typedef boost::function<int(int,int)> arithmetic; 
arithmetic sum = (boost::lambda::_1 + boost::lambda::_2); 
arithmetic max = boost::lambda::if_then_else_return(boost::lambda::_1 > boost::lambda::_2, 
    boost::lambda::_1, boost::lambda::_2); 

int j = sum(3,3); // j ist 6 
int k = max(4,2); // k is 4 

所以,也許這就是你想要存檔。

這也是可能的一個完整的功能。 在這裏,你去。

int FullBodyFunction(int i, int j) 
{ 
    return i+j; 
} 
arithmetic sum2 = boost::bind(&FullBodyFunction, _1, _2); 

這將和sum1一樣。你可以自由地使用整個boost綁定的東西。例如。綁定到對象的方法或任何你想要的。

+0

謝謝。它主要用於短暫的特殊功能嗎?用這種技術寫一個「真實」的功能是否合理? – davka 2011-03-04 16:37:27

+0

什麼是真正的功能?你當然可以綁定功能。你不必使用lambda。 – mkaes 2011-03-09 14:25:08

+0

by「real」我的意思是一個函數不像max那樣簡單,可以這麼說是一個帶有「全身」的函數 – davka 2011-03-09 14:41:58

12

我會給你一個經典的C答案,而不訴諸新穎的C++ 0x玩具。讓我們先來定義一個函數原型開始:

typedef int TWO_ARG_FUNC(int x, int y); 

您可以使用這臺樣機接收函數指針時,如:

void blah(TWO_ARG_FUNC* funcPtr); 

...或者前置聲明函數:

TWO_ARG_FUNC max; 

...但你不能通過只寫原型實現一個功能,例如:

TWO_ARG_FUNC max 
{ 
    ... // bzzt, error! 
} 

然而,並非所有都丟失。您可以執行的功能由第一前置聲明它忠於原型:

TWO_ARG_FUNC max; 

int max(int a, int b) 
{ 
    ... 
} 

另一種辦法是求助於C宏:

#define DEFINE_TWO_ARG_FUNC(funcName) int funcName(int a, int b) 

DEFINE_TWO_ARG_FUNC(max) 
{ 
} 

,你甚至可以使用宏來聲明函數原型,如果你以後想一個指針聲明,以這樣的功能:

typedef DEFINE_TWO_ARG_FUNC(TWO_ARG_FUNC); 
+0

我見過的宏的最佳用法之一,謝謝!最後一行使用typedef非常酷:) – davka 2011-03-04 16:50:35

+1

我不相信'int max(a,b){}'在語義上是有效的。關於函數定義的C規範說明「如果聲明符包含一個標識符列表,則聲明列表中的每個聲明至少應有一個聲明符,這些聲明符只應聲明標識符列表中的標識符,並且聲明標識符列表中的每個標識符「。 (標識符列表是「a,b」,聲明列表是「int a,b;」,如下所示:int max(a,b)int a,b; {...}')。 – 2011-03-04 17:59:56

+0

約翰內斯,你是對的,雖然不是我應該使用舊式C聲明的意義,但從我的理由類型默認爲int而沒有意識到它的意義上說。這就是爲什麼我應該編譯警告,特別是在編寫smartass stackoverflow答案時:-)相應地修復我的答案。 – Ilya 2011-03-05 19:51:28

2

我還沒有找到你正在尋找確切的語法解決方案,但像這樣的工作:

#include <cassert> 

#define arithmetic (int i, int j) -> int 

#define declare(Func, Name) auto Name Func 

#define as_ 

auto sum as_ arithmetic 
{ 
    return i + j; 
}; 

declare(arithmetic, max) 
{ 
    return (i>j) ? i : j; 
}; 

int main() 
{ 
    assert(sum(2, 4) == 6); 
    assert(max(2, 4) == 4); 

    return 0; 
} 
相關問題