【问题标题】:No matching function for lambda with reference argument没有带有引用参数的 lambda 的匹配函数
【发布时间】:2023-01-10 17:55:12
【问题描述】:

我的 MWE 是以下两个文件(main.cpp 和 main.h):

#include "main.h"

int main(int argc, char *argv[]) {
        ThreadMap M;

        M.forEach([&](std::pair<int, int>& Pair) {
                // ...
        });
}
#ifndef MAIN_H
#define MAIN_H

#include <map>
#include <mutex>
#include <shared_mutex>
#include <thread>

class ThreadMap {
        std::map<int, int> Map;
        std::shared_mutex Mutex;
public:
        using iterator = std::map<int, int>::iterator;

        ThreadMap() = default;

        iterator begin() {
                return Map.begin();
        }

        iterator end() {
                return Map.end();
        }

        template <typename Func>
        void forEach(Func &&func) {
                std::unique_lock<std::shared_mutex> Lock(Mutex);
                for (auto& Element : Map) {
                        std::forward<Func>(func)(Element);
                }
        }
};

#endif /* MAIN_H */

测试它需要 C++17:

clang -O2 -c main.cpp -o main.o -std=c++17

我想将一个回调函数传递给我的类,它用同步原语包装一个 STL 容器(代码被大大缩短了,但错误是一样的)。由于我想通过引用遍历容器中的每个元素,我认为我的 lambda 函数还需要将引用参数与 std::pair&lt;int, int&gt;&amp; 匹配。但是,编译给了我:

In file included from main.cpp:1:
./main.h:29:4: error: no matching function for call to object of type '(lambda at main.cpp:6:12)'
                        std::forward<Func>(func)(Element);
                        ^~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:6:4: note: in instantiation of function template specialization 'ThreadMap::forEach<(lambda at main.cpp:6:12)>' requested here
        M.forEach([&](std::pair<int, int>& Pair) {
          ^
main.cpp:6:12: note: candidate function not viable: no known conversion from 'std::pair<const int, int>' to 'std::pair<int, int> &' for 1st argument
        M.forEach([&](std::pair<int, int>& Pair) {
                  ^
1 error generated.

一旦我为我的参数 (-> std::pair&lt;int, int&gt;) 删除了 lambda 函数中的 &amp;,它就可以毫无问题地编译。我不希望我的循环在迭代时生成容器中元素的副本,所以我相信 &amp; 必须保留在 lambda 函数参数中。我在这里错过了什么?

【问题讨论】:

  • std::map&lt;int, int&gt; Map; 不是函数映射。您的函数容器可能需要类似 std::vector&lt;std::function&lt;void (const std::pair&lt;int,int&gt;&amp;)&gt;&gt; 的东西。
  • map&lt;int,int&gt; 的值类型是不是pair&lt;int,int&gt;
  • 边注。从此类返回迭代器可能非常危险。由于可以通过它们访问 map 而无需锁定互斥锁,这可能导致数据竞争,即 UB。如果有人在您通过此类迭代器读取地图时修改地图,即使 const 迭代器也无济于事。
  • 仔细阅读编译器错误。它提到没有从std::pair&lt;const int, int&gt; 到std::pair&lt;int, int&gt;&amp; 的转换。注意const!如果删除&amp;,则编译器可以复制该对,然后允许删除const。如果你只是参考,它不能。

标签: c++ templates lambda c++17


【解决方案1】:

我认为我的 lambda 函数还需要将引用参数与 std::pair<int, int>& 匹配

根据cppref,std::map&lt;Key, T&gt;的值类型是std::pair&lt;const Key, T&gt;。因此,您需要将一个函数接受可以隐式转换为其值类型的类型的参数传递给forEach。

如果你想通过引用传递元素,使用std::pair&lt;const int, int&gt;&amp;,

        M.forEach([&](std::pair<const int, int>& Pair) {
                // ...
        });

Demo

至于为什么要删除参考作品,std::pair&lt;const int, int&gt;被隐式转换为std::pair&lt;int, int&gt;。它正在调用 here 列出的第 5 个构造函数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-28
    • 1970-01-01
    • 1970-01-01
    • 2019-02-10
    • 1970-01-01
    • 2022-06-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多