簡體   English   中英

在 C++ 中將 Lambda 表達式傳遞給 std::function

[英]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);

您傳入u32MutexTimeoutlambda非常好,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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM