【发布时间】:2021-11-10 17:01:06
【问题描述】:
这是从大型代码库移植而来的问题的简化版本。我已经解决了这个问题,但我不喜欢我解决它的方式。
无法编译的有问题的代码是我开始的:
#include <iostream>
#include <cstdlib>
#include <vector>
#include <cassert>
#include <algorithm>
#include <cmath>
#include <array>
#include <utility>
#include <set>
#include <functional>
class S {
public:
int a;
int b;
mutable int c;
void set_c() { c = 222; }
};
struct cmp
{
bool operator()(const S& lhs, const S& rhs) const
{
return !(lhs.a == rhs.a && lhs.b == rhs.b);
}
};
class core {
public:
std::set<S, cmp> set_of_S;
std::function<void()> f;
void set_fn() {
f = [this]() {
auto it = set_of_S.begin();
it->set_c();
};
}
};
int main()
{
core core;
S a {.a = 2, .b = 3, .c = 0};
S b {.a = 2, .b = 3, .c = 0};
S c {.a = 2, .b = 4, .c = 0};
core.set_of_S.insert(a);
core.set_of_S.insert(b);
core.set_of_S.insert(c);
core.set_fn();
core.f();
std::cout << core.set_of_S.size() << '\n';
}
编译错误是:
prog.cc: In lambda function:
prog.cc:37:23: error: passing 'const S' as 'this' argument discards qualifiers [-fpermissive]
it->set_c();
好的,有道理。正如有些人告诉我的那样,您应该使用关键字mutable,因为this 没有被捕获为const,并且迭代器it 现在应该是可修改的(或者至少是我所期望的):
void set_fn() {
f = [this]() mutable {
auto it = set_of_S.begin();
it->set_c();
};
}
这不会编译。这部分对我来说没有意义。所以成员函数不能修改捕获的this 在 lambda 中,但如果你尝试直接在 lambda 编译器中修改S::c 认为没关系。什么?对我来说没有意义。
当我改变时:
void set_c() { c = 222; }
到
void set_c() const { c = 222; }
它最终会编译,但我不喜欢这个解决方案,因为我们不得不修改原始函数签名,只是因为 lambda 不接受它并且它使其可读性降低。我将 lambdas 视为一种工具,而不是你必须设计的东西。我尝试将mutable 关键字放在各处,但无法编译。而且我认为应该有一种方法可以允许成员函数在 lambda 中修改它自己的状态。
是我遗漏了什么还是这是一个编译器错误?
这里是 wandbox 中有问题的代码:https://wandbox.org/permlink/qzFMW6WIRiKyY3Dj
我知道有人问过这个问题:error: passing xxx as 'this' argument of xxx discards qualifiers,但答案不会讨论使用mutable,据我了解应该可以解决这类情况。
【问题讨论】:
-
你不修改指针
this,所以mutable这个lambda没用。 -
不是错误。
std::set<S, cmp>::begin()返回 constant iterator。 -
@drew-dormann 如果取消注释
it->set_c(),为什么it->c = 300会起作用? wandbox.org/permlink/O9vFnhEO1RKZ9YjX -
@OVOT
it->c有效,因为c是可变的。但是it->set_c()不会,因为set_c是一个非常量函数,所以不能在 const 对象上调用它 -
告诉编译器的方法是将函数标记为
const,即“可以在 const 对象上调用此函数”