微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

将“const std::map<int, bool>”作为“this”参数传递会丢弃 lambda 函数

如何解决将“const std::map<int, bool>”作为“this”参数传递会丢弃 lambda 函数

这是我收到错误的基本代码片段:

错误:将‘const std::map’作为‘this’参数传递会丢弃限定符[-fpermissive]`

struct Point {
    float x;
    float y;
    int id;
    Point(float x,float y,float id) : x(x),y(y),id(id) {}
};

void removePoints(std::vector<Point> &points_vec) {
    std::map<int,bool> my_map;
    for (const auto& pt : points_vec) {
        if(pt.id < 0) 
            my_map[pt.id] = true;
        else
            my_map[pt.id] = false;
    }

    points_vec.erase(std::remove_if(points_vec.begin(),points_vec.end(),[map_lambda = my_map] (const Point pt) -> bool {
        return map_lambda[pt.id];
    }),points_vec.end());
}

int main(int argc,char const *argv[]) {
    std::vector<Point> points_vec;
    points_vec.push_back(Point(1,2,0));
    points_vec.push_back(Point(1,5,-1));
    points_vec.push_back(Point(3,3,-1));
    points_vec.push_back(Point(4,9,2));
    points_vec.push_back(Point(0,1,3));
    points_vec.push_back(Point(-1,7,-2));

    std::cout << points_vec.size() << std::endl;
    removePoints(points_vec);
    std::cout << points_vec.size() << std::endl;
    
    return 0;
}

注意:我知道我可以在不使用 std::map 的情况下删除点,但上面的代码片段只是一个更大问题的示例。

我检查了一些关于类似错误的问题:

  1. error: passing ‘const std::map<int,int>’ as ‘this’ argument discards qualifiers [-fpermissive]
  2. C++ "error: passing 'const std::map<int,std::basic_string<char> >' as 'this' argument of ..."

但在它们两者中,这是因为 std::map 已被声明为 const。另一方面,我尝试使用/访问的 map 尚未声明为 const,我的错误也与 lambda 相关。如您所见,我正在 lambda 捕获列表中创建原始 my_map 的副本作为 map_lambda = my_map。那么,为什么我会收到此 -fpermissive 错误?或者,当我们在 lambda 中捕获某些内容时,它是否会自动转换为 const

详细的错误信息:

main.cpp: In lambda function:
main.cpp:26:32: error: passing ‘const std::map<int,bool>’ as ‘this’ argument discards qualifiers [-fpermissive]
         return map_lambda[pt.id];
                                ^
In file included from /usr/include/c++/7/map:61:0,from main.cpp:2:
/usr/include/c++/7/bits/stl_map.h:484:7: note:   in call to ‘std::map<_Key,_Tp,_Compare,_Alloc>::mapped_type& std::map<_Key,_Alloc>::operator[](const key_type&) [with _Key = int; _Tp = bool; _Compare = std::less<int>; _Alloc = std::allocator<std::pair<const int,bool> >; std::map<_Key,_Alloc>::mapped_type = bool; std::map<_Key,_Alloc>::key_type = int]’
       operator[](const key_type& __k)
       ^~~~~~~~

顺便说一句,我知道 operator[] 返回值如果键已经存在,否则它会创建一个新键并插入值(并返回它)。但是为什么 conststd::map::operator[] 会给出编译错误?它不应该更像是运行时错误吗?

解决方法

lambda 捕获的所有变量都是隐式 const,除非您将 lambda 标记为 mutable。地图的 const 没有 operator[] 重载,因为它可能总是改变地图(创建新的键值对)。

如果您确定地图中存在每个 pt.id,请将 operator [] 更改为 at() 调用:

[map_lambda = my_map] (const Point pt) -> bool {
        return map_lambda.at(pt.id);
}

如果您想在地图中创建不存在的键,请将 lambda 更改为 mutable

[map_lambda = my_map] (const Point pt) mutable -> bool {
        return map_lambda[pt.id];
}
,

问题在于这个语句中使用的 lambda 表达式

 points_vec.erase(std::remove_if(points_vec.begin(),points_vec.end(),[map_lambda = my_map] (const Point pt) -> bool {
        return map_lambda[pt.id];
    }),points_vec.end());

是不可变的。所以 map_lambda 被认为是一个常量对象。但是下标运算符要求对象是可修改的。也就是说,您不能将下标运算符与类模板 std::map 的常量对象一起使用。

您应该将 map_lambda 声明为对 my_map 的非常量引用。

那就是像改变 lambda 一样

[&map_lambda = my_map] (const Point pt) -> bool {
        return map_lambda[pt.id];
    }

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。