2017-04-25 109 views
1

時可以這麼推斷的類型,我有一種方法及其一類的過載,這樣寫的:編譯器無法使用std ::函數

bool my_for_each(someIterator begin, someIterator end, bool (*_lambda)(someIterator)); 

void my_for_each(someIterator begin, someIterator end, void (*_lambda)(someIterator)); 

正如你看到的,唯一的區別是簽名一個傳遞的函數,也就是它的返回類型。 雖然上面的代碼工作完全正常,當我把它稱爲:

my_for_each(iteratorBegin, iteratorEnd, [](someIterator) {; }); // calls void version 

my_for_each(iteratorBegin, iteratorEnd, [](someIterator)->bool {return false; }); // calls bool version 

...,如果我寫的my_for_each功能如下:

bool my_for_each(someIterator begin, someIterator end, std::function<bool(someIterator)> _lambda); 

void my_for_each(someIterator begin, someIterator end, std::function<void(someIterator)> _lambda); 

的代碼編譯失敗,如果我調用該函數以同樣的方式(C2668模糊調用重載函數)。雖然,如果我手動投功能:

my_for_each(iteratorBegin, iteratorEnd, static_cast<std::function<void(someIterator)>>([](someIterator) {; })); //calls void version 

my_for_each(iteratorBegin, iteratorEnd, static_cast<std::function<bool(someIterator)>>([](someIterator) -> bool { return false; })); //calls bool version 

代碼工作完全正常。所以我只是想知道:

  1. 爲什麼正常的函數指針類型扣除「比std模板更強」?
  2. 是否有一些有點解決方法仍然使用更通用的版本,而不是手動投射參數?

編譯器是VS2015。

謝謝,祝你有美好的一天!

+0

@FrançoisAndrieux固定的,只是抄寫錯誤 – Alfaix

+0

什麼是返回值的'my_for_each'功能的含義是什麼? –

+0

它似乎是兩個形成一個範圍的迭代器,它接受一個迭代器並對它做些什麼。我不確定第二個版本中的所有「布爾」是怎麼做的(推測可能是an和or或者operation)。 –

回答

3

std::function和lambda具有不同的類型,這意味着第二個示例需要從lambda類型到std::function的隱式轉換。

的問題是,它返回bool拉姆達可以隱式轉換到兩個std::function<bool(T)>std::function<void(T)>,因此兩個重載同樣有效的選擇你的電話,導致多義性錯誤。當您手動將它們投射到適當的std::function時,明確解決了歧義。

編輯:解決方法

您可以通過提供另外模板重載接受任何類型的可調用類型的解決這個問題,推斷出該調用類型的返回類型,並自動瓶坯的演員。我已將someIterator更改爲一般性的模板參數。由於您尚未提供您的my_for_each函數的實現細節,因此我省略了這些實現。由於您似乎只想支持voidbool返回類型,因此我添加了static_assert以在發生不支持的返回類型時生成明確的編譯器錯誤。

#include <functional> 
#include <type_traits> 

// Implement for std::function<bool(iter)> 
template<class I> 
bool my_for_each(I begin, I end, std::function<bool(I)> lambda); 

// Implement for std::function<void(iter)> 
template<class I> 
void my_for_each(I begin, I end, std::function<void(I)> lambda); 

// Dispatch to the right overload 
template<class T, class I> 
auto my_for_each(I begin, I end, T&& lambda) 
{ 
    using return_type = decltype(lambda(begin)); // Obtain the return type of lambda 
    static_assert(std::is_same<return_type, bool>::value || std::is_same<return_type, void>::value, 
     "my_for_each only accepts function objects that return void or bool"); 
    using function_type = std::function<return_type(I)>; // The type to cast lambda to 
    return my_for_each(begin, end, function_type(std::forward<T>(lambda))); // Preform the cast 
} 
+1

修復將改善這個答案。 – Yakk

+0

所以,如果我想使用自己的可調用對象,我必須static_cast他們每次,是否正確? – Alfaix

+0

@Alfaix我已經修改了答案,以避免每次都必須手動投射。 –

2

原因是非捕獲lambdas只能轉換爲函數指針,它會接受使用類型的參數。

另一方面,std::function有一個模板化的構造函數,它接受所有的東西。因此std::function<bool...>std::function<void ...>可以從您的lambda創建,用於my_for_each的重載分辨率。 (注意,雖然它不可能創建這些對象)。

相關問題