2012-12-29 25 views
2

爲什麼第二個例子不起作用?有沒有辦法讓第二個例子可以工作,同時仍然可以將lambda或函數轉換爲介質以便稍後參考?拉姆達的普通類型和功能可供參考

// Types I'm using 
typedef void (*ANY_FUNC)(...); 
typedef void (*VOID_FUNC)(); 

這工作

void call_void(VOID_FUNC func) { 
    ((ANY_FUNC)func)(); 
}; 

// ... 

call_void([]() { /* do something */ }); 

這不

template <typename fn> 
void call_any(fn func) { 
    ((ANY_FUNC)func)(); 
}; 

// ... 

call_any([]() { /* do something */ }); 

請忽略的事實是,你永遠不會需要使用第二個例子,現在如何。它僅用於演示(相對代碼)。

這兩個示例都使用函數指針而不是lambda表達式。

+1

順便說一句:避免用C風格的轉換,因爲他們甚至可以工作的時候,他們不應該。相反,請執行'ANY_FUNC f = func; f();'使演員(如果它發生和工作)是隱式的而不強迫任何事情。這在運行時沒有開銷。 – Yakk

回答

2

As long as you are declaring a template you can just use the incoming function object直接。此外,你應該聲明你的函數參數作爲參考,不作按值:

template <typename fn> 
void call_any(fn&& func) { 
    func(); 
}; 

如果你要調用帶有參數的功能,你可以這樣做:

template <typename fn, typename... Args> 
void call_any_many(fn&& func, Args&&... args) { 
    func(std::forward<Args>(args)...); 
}; 

用例:

int main() 
{ 
    call_void([]() { std::cout << "Hello, void World!" << std::endl; }); 
    call_any([]() { std::cout << "Hello, any World!" << std::endl; }); 
    call_any_many([](int x) { std::cout << "Hello, any many World-" << x << "!" << std::endl; }, 1234); 

    return 0; 
} 

但是,如果你的意圖是存儲一些函數指針而不是直接調用它們,我建議使用標頭中的std::function。你可以看到一些信息和示例從這裏:http://en.cppreference.com/w/cpp/utility/functional/function

例如:

#include <iostream> 
#include <functional> 

int main() 
{ 
    std::function<void()> anyf = []() { std::cout << "Hello, any World!" << std::endl; }; 
    std::function<void(int)> intf = [](int x) { std::cout << "Hello, any many World-" << x << "!" << std::endl; }; 

    anyf(); 
    intf(1234); 

    return 0; 
} 
0

我不認爲他們中的任何一個真的的作品,除了在一些編譯器上偶然的機會。

與lambda的區別在於它可以轉換爲函數指針,但它不是一個。模板版本會注意到這種差異,並且fn未被推斷爲VOID_FUNC

0

Lambda表達式是隱式轉換爲函數指針(但只有當他們沒有捕捉到任何東西),所以只是改變call_any的參數的函數指針:

void call_any(ANY_FUNC func) 
{ 
    (*func)(); 
} 

你會需要的lambda來調用它適當的類型:因爲他們是作爲非類型安全的,你可以得到

call_any([](...) { /* ... */ }); 

但可變長度參數列表(也稱爲可變參數)是壞的。與函數指針一樣:它們是非面向對象的。你應該想到一個替代機制,可能涉及可變參數模板和多態性(虛擬方法)

0

第一種方法是將lambda轉換爲具有相應參數和返回類型的函數指針,然後將其轉換爲可變參數函數,而第二種試圖將lambda直接轉換爲可變參數函數(即,沒有相應參數類型的函數)。

第一個示例中的兩個轉換允許*,但第二個轉換不是。

*注意,轉換符號您使用函數指針類型之間轉換結束了像reinterpret_cast工作的規定:「一個函數指針可以顯式轉換爲不同類型的函數指針調用的影響函數通過一個指向函數類型(8.3.5)的指針與函數的定義中使用的類型不一樣是未定義的。「因此,第一個示例代碼具有未定義的行爲。