[英]Passing a Lambda Expression to std::function in C++
我目前正在為 lambda 表達式苦苦掙扎。 我創建了一個 ConcurrentDictionary,它用互斥體包裝 std::map。 現在我想導出匹配指定條件的所有元素。
template<typename MutexTypeT, typename Key_Type_T, typename Mapped_Type_T>
class CConcurrentDictionary
{
public:
///Constructor
CConcurrentDictionary();
class CSingleElement
{
public:
///the key
Key_Type_T key = { };
///THe Mapped Type
Mapped_Type_T mapped_type = { };
};
template<typename ...Args_T>
std::vector<CSingleElement> exportSelectedData(
const uint32_t u32MutexTimeout,
std::function<bool(const CSingleElement, Args_T &&...)> compareFn,
Args_T&&...CompareArgs...) const;
}
template<typename MutexTypeT, typename Key_Type_T, typename Mapped_Type_T>
template<typename ...Args_T>
auto CConcurrentDictionary<MutexTypeT, Key_Type_T, Mapped_Type_T>::exportSelectedData(
const uint32_t u32MutexTimeout,
std::function<bool(const CSingleElement, Args_T &&...)> compareFn,
Args_T&&...CompareArgs...) const ->
std::vector<CSingleElement>
{
//lock mutex...
std::vector<CSingleElement> vecRes;
for (const auto &single_element : dictionary)
{
if(compareFn(single_element, CompareArgs...))
{
//this element mathes the preconditions
vecRes.push_back(single_element);
}
}
return vecRes;
}
但是,當我嘗試像這樣使用此類時
class CTraceCmdDuration
{
public:
///Cmd Datatype
using CmdType_T = uint32_t;
class CCmdSummary
{
public:
/**
* SIngle Long Running Cmd Summary
* @param CmdIdArg Cmd ID
* @param u32MaxCmdDurationArg Max CmdDuration
*/
CCmdSummary(const CmdType_T CmdIdArg, const uint32_t u32MaxCmdDurationArg);
///Id of this cmd
const CmdType_T CmdId;
///Duration of this cmd
const uint32_t u32MaxCmdDuration;
};
/**
* Exports all Cmds to a vector with took longer than u32MaxCmdDuration
* @param u32MaxCmdDuration Maximal Cmd Processing duration time. Cmds that took longer than this will be exported
* @param u32MutexTimeout Mutex Timeout
* @return List with all long running cmds
*/
std::vector<CCmdSummary> ExportLongRunningCmds(const uint32_t u32MaxCmdDuration, const uint32_t u32MutexTimeout) const;
}
auto CTraceCmdDuration::ExportLongRunningCmds(const uint32_t u32MaxCmdDuration, const uint32_t u32MutexTimeout) const ->
std::vector<CCmdSummary>
{
auto lambda = [u32MaxCmdDuration](const CombinedDictElement& singleElement)
{
const bool bRes = (u32MaxCmdDuration < singleElement.mapped_type.u32MaxProcessingDuration);
return bRes;
};
auto vecRes = dict.exportSelectedData(u32MutexTimeout, lambda, u32MaxCmdDuration);
return vecRes;
}
不幸的是,這不會產生對函數錯誤的匹配調用
error: no matching function for call to 'NConcurrent_Container::CConcurrentDictionary<NMutex::CEmbos_Mutex, long unsigned int, NDebug::CTraceCmdDuration::CProcessingInfo>::exportSelectedData(const uint32_t&, NDebug::CTraceCmdDuration::ExportLongRunningCmds(uint32_t, uint32_t) const::__lambda0&, const uint32_t&) const'
auto vecRes = dict.exportSelectedData(u32MutexTimeout, lambda, u32MaxCmdDuration);
我的 lambda 表達式有什么問題? 想法是將最大允許持續時間作為捕獲傳遞,並將 std::map 中的每個存儲元素作為參數傳遞。
或者你有更好的idea? 你能幫我一下嗎?
編輯:感謝您的回答,如果我傳遞一個靜態函數,這很有效,但是我如何將 lambda 作為模板參數傳遞?
static bool CompareDuaration(const CSingleElement&singleElement, const uint32_t u32MaxDuration);
auto CTraceCmdDuration::ExportLongRunningCmds(const uint32_t u32MaxCmdDuration, const uint32_t u32MutexTimeout) const ->
std::vector<CombinedDictElement>
{
auto vecRes = dict.exportSelectedData(u32MutexTimeout, lambda, u32MaxCmdDuration);
return vecRes;
}
這有效但
auto CTraceCmdDuration::ExportLongRunningCmds(const uint32_t u32MaxCmdDuration, const uint32_t u32MutexTimeout) const ->
std::vector<CombinedDictElement>
{
auto lambda = [u32MaxCmdDuration](const CombinedDictElement& singleElement)
{
const bool bRes = (u32MaxCmdDuration < singleElement.mapped_type.u32MaxProcessingDuration);
return bRes;
};
auto vecRes = dict.exportSelectedData(u32MutexTimeout, lambda, u32MaxCmdDuration);
return vecRes;
}
給我一個編譯錯誤
error: no match for call to '(CTraceCmdDuration::ExportLongRunningCmds(uint32_t, uint32_t) const::__lambda0) (CConcurrentDictionary<NMutex::CEmbos_Mutex, long unsigned int, CTraceCmdDuration::CProcessingInfo>::CSingleElement&, const long unsigned int&)'
if(compareFn(singleElement, compareArgs...))
它的接縫就像將 lambdas 傳遞給模板並不能很好地工作。 我錯過了什么?
您遇到的問題可以簡化為:
#include <functional>
template <typename ...Args>
void foo(std::function<bool(Args...)>) { }
int main()
{
foo([](int, int) { return true; });
}
這將無法編譯。 原因是std::function
的模板參數的類型推導失敗。
您希望將某種std::function
作為參數傳遞。 由於沒有傳入std::function
對象(無論確切的實例化),編譯器嘗試構造std::function
並通過調用std::function
的構造std::function
推斷模板參數類型。 問題由此開始。 在這種情況下匹配的構造函數將是:
template <typename F>
function(F f);
您會注意到構造函數本身也是模板化的。 編譯器可以成功地將F
推導出為 lambda,但由於F
是構造函數的模板參數,因此無法推導出類本身std::function
的模板參數。
此外,在該構造函數上引用cppreference :
[...] 此構造函數不參與重載決議,除非 f 對於參數類型 Args... 是可調用的,並且返回類型 R。[...]
這意味着此構造函數的存在基於是否可以使用類模板參數Args...
調用F
,但由於這些參數未明確定義且無法推導,因此無論如何此構造函數都不可用。
由於您僅在exportSelectedData
使用該std::function
,只需將其exportSelectedData
模板參數(拋棄std::function
部分):
template<typename Func, typename ...Args_T>
std::vector<CSingleElement> exportSelectedData(uint32_t u32MutexTimeout, Func compareFn, Args_T const&...) const;
您還應該將Args_T&&
更改為Args_T const&
因為您不是簡單地轉發這些參數而是在循環中重用它們。
關於編輯中的后續問題:想想你在做什么。
首先聲明一個 lambda:
auto lambda = [u32MaxCmdDuration](const CombinedDictElement& singleElement) { /* ... */ };
現在想想那個 lambda 的簽名。 你返回一個布爾值,所以返回類型是bool
(到目前為止很好)。 您在捕獲子句中使用u32MaxCmdDuration
並使用一個參數singleElement
。 讓我們刪除所有額外的限定符並查看簽名:
bool(CombinedDictElement) // take a CombinedDictElement and return a bool
接下來,我們看一下exportSelectedData
的調用:
exportSelectedData(u32MutexTimeout, lambda, u32MaxCmdDuration);
您傳入u32MutexTimeout
和lambda
非常好,lambda 被compareFn
捕獲。 第三個參數是u32MaxCmdDuration
,它由模板中的...compareArgs
捕獲。 現在讓我們看看在exportSelectedData
實際調用 lambda 的exportSelectedData
:
if (compareFn(singleElement, compareArgs...)) // ...
你希望compareFn
在這里有什么簽名? 如果我們擴展...compareArgs
包(再次,為了簡單起見,刪除額外的限定符),簽名看起來像這樣:
bool(CombinedDictElement, unsigned int) // take a CombinedDictElement and an unsigned int and return a bool
這是 lambda 簽名:
bool(CombinedDictElement)
你發現問題了嗎? lambda 捕獲u32MaxCmdDuration
作為狀態捕獲,而exportSelectedData
期望它作為參數(因為您將它作為附加參數傳遞給exportSelectedData
)。 顯然,簽名彼此不同,因此我們必須更改其中一個以匹配另一個。 這在你的情況下相當容易,要么
更改您的 lambda 以將u32MaxCmdDuration
作為參數:
auto lambda = [](const CombinedDictElement& singleElement, unsigned int u32MaxCmdDuration)
或者
刪除u32MaxCmdDuration
作為exportSelectedData
調用的附加參數:
exportSelectedData(u32MutexTimeout, lambda);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.