std::set_difference 在地图和矢量上引发转换错误

std::set_difference on map and a vector throws conversion errors

下面的代码应该计算地图和矢量的差异

std::map<int, int> cursorMap;
QVector<User> userList;
...
std::vector<int> offlineUserIds{};
std::vector<int>::iterator it;
it = std::set_difference(cursorMap.begin(), cursorMap.end(), userList.begin(), userList.end(), offlineUserIds.begin(),
[](const std::pair<int, int> &e, const User &u){ return u.getId() == e.first; });

在调用 set_difference 之前,userList 被转换为 std::vector 并排序。问题是它给了我以下错误:

error: cannot convert 'std::pair<const int, int>' to 'int' in assignment
...
error: no match for call to '(TextEditor::updateCursorMap(QVector<User>)::<lambda(const std::pair<int, int>&, const User&)>) (User&, std::pair<const int, int>&)'
         { return bool(_M_comp(*__it1, *__it2)); }
...
note: candidate: 'TextEditor::updateCursorMap(QVector<User>)::<lambda(const std::pair<int, int>&, const User&)>'
...
     it = std::set_difference(cursorMap.begin(), cursorMap.end(), userList.begin(), userList.end(), offlineUserIds.begin(), [](const std::pair<int, int> &e, const User &u){ return u.getId() == e.first; });
...
note:   no known conversion for argument 1 from 'User' to 'const std::pair<int, int>&'

编辑:

我试过下面的代码

std::map<int, int> cursorMap;
QVector<User> userList;
...
std::vector<std::pair<int, int>> offlineUserIds{};
std::vector<std::pair<int, int>>::iterator it;
it = std::set_difference(cursorMap.begin(), cursorMap.end(), userList.begin(), userList.end(), offlineUserIds.begin(), [](const std::pair<int, int> &e, const User &u){ return e.first < u.getId(); });

但现在它给了我

note: candidate: 'TextEditor::updateCursorMap(QVector<User>)::<lambda(const std::pair<int, int>&, const User&)>'
     it = std::set_difference(cursorMap.begin(), cursorMap.end(), userList.begin(), userList.end(), offlineUserIds.begin(), [](const std::pair<int, int> &e, const User &u){ return e.first < u.getId(); });
...
note:   no known conversion for argument 1 from 'User' to 'const std::pair<int, int>&'

编辑 2:

这是一个最小的可重现示例:

#include <iostream>
#include <vector>
#include <map>
#include <algorithm>

class User {
    int id;
public:
    int getId() const { return id; }
};


int main() {
    std::vector<User> newUserList{};
    std::map<int, int> cursorMap{};
    std::vector<User> userList = std::vector(newUserList.begin(), newUserList.end());
    std::sort(userList.begin(), userList.end(), [](const User &u1, const User &u2) { return u1.getId() < u2.getId(); });

    std::vector<std::pair<int, int>> offlineUserIds{};
    std::vector<std::pair<int, int>>::iterator it;
    it = std::set_difference(cursorMap.begin(), cursorMap.end(), userList.begin(), userList.end(), offlineUserIds.begin(), [](std::pair<int, int> e, User u){ return e.first < u.getId(); });

    return 0;
}

构建输出

In file included from C:/Qt/Tools/mingw810_64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/bits/stl_algobase.h:71,
                 from C:/Qt/Tools/mingw810_64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/bits/char_traits.h:39,
                 from C:/Qt/Tools/mingw810_64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/ios:40,
                 from C:/Qt/Tools/mingw810_64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/ostream:38,
                 from C:/Qt/Tools/mingw810_64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/iostream:39,
                 from D:\asant\workspace\CLionProjects\untitled\main.cpp:1:
C:/Qt/Tools/mingw810_64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/bits/predefined_ops.h: In instantiation of 'constexpr bool __gnu_cxx::__ops::_Iter_comp_iter<_Compare>::operator()(_Iterator1, _Iterator2) [with _Iterator1 = __gnu_cxx::__normal_iterator<User*, std::vector<User> >; _Iterator2 = std::_Rb_tree_iterator<std::pair<const int, int> >; _Compare = main()::<lambda(std::pair<int, int>, User)>]':
C:/Qt/Tools/mingw810_64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/bits/stl_algo.h:5343:17:   required from '_OutputIterator std::__set_difference(_InputIterator1, _InputIterator1, _InputIterator2, _InputIterator2, _OutputIterator, _Compare) [with _InputIterator1 = std::_Rb_tree_iterator<std::pair<const int, int> >; _InputIterator2 = __gnu_cxx::__normal_iterator<User*, std::vector<User> >; _OutputIterator = __gnu_cxx::__normal_iterator<std::pair<int, int>*, std::vector<std::pair<int, int> > >; _Compare = __gnu_cxx::__ops::_Iter_comp_iter<main()::<lambda(std::pair<int, int>, User)> >]'
C:/Qt/Tools/mingw810_64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/bits/stl_algo.h:5447:46:   required from '_OIter std::set_difference(_IIter1, _IIter1, _IIter2, _IIter2, _OIter, _Compare) [with _IIter1 = std::_Rb_tree_iterator<std::pair<const int, int> >; _IIter2 = __gnu_cxx::__normal_iterator<User*, std::vector<User> >; _OIter = __gnu_cxx::__normal_iterator<std::pair<int, int>*, std::vector<std::pair<int, int> > >; _Compare = main()::<lambda(std::pair<int, int>, User)>]'
D:\asant\workspace\CLionProjects\untitled\main.cpp:21:188:   required from here
C:/Qt/Tools/mingw810_64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/bits/predefined_ops.h:143:18: error: no match for call to '(main()::<lambda(std::pair<int, int>, User)>) (User&, std::pair<const int, int>&)'
         { return bool(_M_comp(*__it1, *__it2)); }
                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:/Qt/Tools/mingw810_64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/bits/predefined_ops.h:143:18: note: candidate: 'bool (*)(std::pair<int, int>, User)' <conversion>
C:/Qt/Tools/mingw810_64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/bits/predefined_ops.h:143:18: note:   candidate expects 3 arguments, 3 provided
D:\asant\workspace\CLionProjects\untitled\main.cpp:21:156: note: candidate: 'main()::<lambda(std::pair<int, int>, User)>'
     it = std::set_difference(cursorMap.begin(), cursorMap.end(), userList.begin(), userList.end(), offlineUserIds.begin(), [](std::pair<int, int> e, User u){ return e.first < u.getId(); });
                                                                                                                                                            ^
D:\asant\workspace\CLionProjects\untitled\main.cpp:21:156: note:   no known conversion for argument 1 from 'User' to 'std::pair<int, int>'
mingw32-make.exe[3]: *** [CMakeFiles\untitled.dir\build.make:82: CMakeFiles/untitled.dir/main.cpp.obj] Error 1
mingw32-make.exe[2]: *** [CMakeFiles\Makefile2:95: CMakeFiles/untitled.dir/all] Error 2
mingw32-make.exe[1]: *** [CMakeFiles\Makefile2:102: CMakeFiles/untitled.dir/rule] Error 2
mingw32-make.exe: *** [Makefile:137: untitled] Error 2

set_difference 的比较器 cmpLessCompare 并且将检查等价性 类似于:

 pair<int, int> e == User u <==> !(e < u) && !(u < e) <==> !cmp(e,u) && !cmp(u,e)

这只有在 eu 可以相互转换时才有效,但事实并非如此。

模板的值类型classstd::map定义为

typedef pair<const Key, T> value_type;

但是 class std::vector<int> 的值类型是 int.

您不能将类型 std::pair 的对象分配给类型 int 的对象。

所以编译器报错。

此外,可以使用传递参数的任意顺序调用比较函数。因此,编译器可能会再次发出错误,指出使用了无效参数,因为参数的类型不同,并且没有从一种类型到另一种类型的隐式转换..

您可能想要滚动自己的差异函数或为用户提供转换运算符,这将允许 set_difference 比较对和用户。

set_difference需要相互转换和插入Type1到输出序列的能力。使用 std::map 相互转换是不可能的,因为在这种情况下转换运算符必须是 std::pair 的成员。

我认为您的 lambda 以错误的顺序获取参数。试试下面的。

[](const User &u, const std::pair<int, int> &e){ return u.getId() == e.first; });

出于我不知道的原因:

The types Type1 and Type2 must be such that objects of types InputIt1 and InputIt2 can be dereferenced and then implicitly converted to both Type1 and Type2

参见cppreference。 Parameters -> comp 下的最后一句话。被我高亮了。