c++ - 在 C++ 中将 Lambda 表达式传递给 std::function
问题描述
我目前正在努力使用 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 中的每个存储元素作为参数传递。
或者你有更好的想法?你能帮帮我吗?
编辑:谢谢你的回答,如果我传递一个静态函数,这很有效,但我如何将 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
失败。
您期望 astd::function
作为参数传递。由于没有std::function
传入任何对象(无论确切的实例化),编译器会尝试构造 astd::function
并通过调用 的构造函数来推断模板参数类型std::function
。问题从这里开始。在这种情况下,匹配的构造函数将是:
template <typename F>
function(F f);
您会注意到构造函数本身也是模板化的。编译器可以成功推断F
为 lambda,但由于F
是构造函数的模板参数,std::function
因此无法推断类本身的模板参数。
此外,在该构造函数上引用cppreference :
[...]此构造函数不参与重载决议,除非 f 对于参数类型 Args... 和返回类型 R 是可调用的。 [...]
这意味着此构造函数的存在取决于是否F
可以使用类模板参数调用Args...
,但由于这些参数没有显式定义且无法推断,因此该构造函数无论如何都不可用。
解决方案
由于您仅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
capture -clause并接受一个 argument singleElement
。让我们删除所有额外的限定符并查看签名:
bool(CombinedDictElement) // take a CombinedDictElement and return a bool
接下来,我们看一下 的调用exportSelectedData
:
exportSelectedData(u32MutexTimeout, lambda, u32MaxCmdDuration);
你传入,u32MutexTimeout
这lambda
很好,lambda 被compareFn
. 第三个参数是在您的模板u32MaxCmdDuration
中捕获的。...compareArgs
现在让我们看看你在哪里实际调用了里面的 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)
或者
remove
u32MaxCmdDuration
作为exportSelectedData
调用的附加参数:exportSelectedData(u32MutexTimeout, lambda);
推荐阅读
- next.js - 在 _app 中模拟 Next.js getInitialProps
- r - 与 df 比较并根据匹配行填充 col
- c# - 按下按钮时如何从集合视图中获取相应的对象?
- swift4 - 如何摆脱出现在顶部和表格视图之间的空 UITableCell
- azure-storage - 使用 Azure Function 和 Key Vault 管理 Azure 存储帐户密钥的轮换
- sql - SQL - 使用窗口函数创建滞后变量
- java - 如何在 jdbcTemplate 中为具有相同值的多个参数标记传递参数?
- swift4 - 数组(字符串内部)转换,Swift 4
- sql - 在特定列 postgres 中选择具有最大值的组中的行
- java - 在检查数据类型时用 Java 解析数据