【发布时间】: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<int, int>& 匹配。但是,编译给了我:
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<int, int>) 删除了 lambda 函数中的 &,它就可以毫无问题地编译。我不希望我的循环在迭代时生成容器中元素的副本,所以我相信 & 必须保留在 lambda 函数参数中。我在这里错过了什么?
【问题讨论】:
-
std::map<int, int> Map;不是函数映射。您的函数容器可能需要类似std::vector<std::function<void (const std::pair<int,int>&)>>的东西。 -
map<int,int>的值类型是不是pair<int,int> -
边注。从此类返回迭代器可能非常危险。由于可以通过它们访问 map 而无需锁定互斥锁,这可能导致数据竞争,即 UB。如果有人在您通过此类迭代器读取地图时修改地图,即使
const迭代器也无济于事。 -
仔细阅读编译器错误。它提到没有从
std::pair<const int, int>到std::pair<int, int>&的转换。注意const!如果删除&,则编译器可以复制该对,然后允许删除const。如果你只是参考,它不能。
标签: c++ templates lambda c++17