无法修改基于范围的循环中引用的值
Can't modify the value of a reference in Range based loop
我正在做一个布尔最小化的学校项目,在这里我想删除我的用户定义的一组元素的一些元素 class。
这是错误发生的地方:
(dc 和 PI 都是我的 class Term
的集合,通过引用传递给这个函数。std::set<Term>& dc, PI
)
for (const auto& n : dc) {
for (const auto& i : n.getMinterm()) {
m[i] = 0;
for (auto &x : PI) {
x.delMinterm(i);
}
}
}
错误信息是:
- 错误(活动)E1086 对象具有与成员函数“Term::delMinterm”不兼容的类型限定符
- 错误 C2662 'void Term::delMinterm(int)': 无法将 'this' 指针从 'const Term' 转换为 'Term &'
这是我class的内容:
class Term {
private:
int group = 0;
int literal = 0;
std::string term;
std::set<int>minterm;
bool isDontCare;
bool merged;
};
函数 delMintern(int)
只是从集合 minterm
中删除选定的元素。
Though I didn't use "const auto&" but "auto&", it still shown as a const object.
我试过去掉'&'但是它只是创建了一个本地副本,但是,我想直接修改原来的。
我也试过类似的东西:
for (auto x : PI) {
PI.erase(x);
x.delMinterm(i);
PI.insert(x);
}
但它导致了“读取访问冲突”错误。
您不能修改对 x
的引用,因为它是 const
。它是常量,因为通过循环迭代 std::set
只给出常量值。
在我的答案末尾查看带有 const_cast
示例代码的解决方案。
已知 std::set
将所有条目存储在排序树中。
现在想象一下,如果你可以在循环迭代时修改一个变量,这意味着修改后 std::set
的排序顺序可能会改变。但是 std::set
应该始终保持其树的不变性,因此它不允许进行任何修改,因此在迭代时只给出 const
值。
如果你真的需要修改集合条目,那么你必须从集合中取出它,从集合中删除,然后再次添加到集合中。即使你修改后排序没有改变,你仍然需要重新插入集合。
但是有一个 hacky 解决方法 - 您可以使您的方法 delMinentry
具有 const
修饰符。然后它修改的所有字段都应标记为 mutable
。可变字段允许从 const
方法进行修改。 std::set
允许在迭代时调用 const
方法。
还有一个变通方法——你将 delMinterm()
作为 const
方法,但在这个方法中做 const_cast<Term &>(*this).delMintermNonConst()
,换句话说,你可以从 const 方法调用非 const 方法如果你这样做 const_cast
。如果您确定要做什么,也可以直接在循环变量上执行 const 转换,换句话说,如果您以 std::set
排序顺序不变的方式修改 Term:
for (auto &x : PI) {
const_cast<Term &>(x).delMinterm(i);
}
如果 delMinterm()
导致对 Term 的这种修改,之后 std::set
的顺序可能会改变,那么您不能在上面的代码中执行 const_cast
。换句话说,如果在 delMinterm 之后你的 operator <
可能会在术语之间给出不同的结果,那么你不能做这个 const 转换,你必须重新插入到集合中(删除 Term 并再次添加)。
另外不要忘记,在重新插入 set 后,您必须从头开始重新执行 set 迭代循环,因为更改内部结构后,您无法继续迭代循环 运行,迭代器将失效。
如果 set 的顺序改变(因此你不能做 const_cast
)那么你必须重新插入 set 的值,通过将值复制到 vector,通过 delMinterm() 修改它们,复制回来设置,像这样:
std::vector<Term> scopy(PI.cbegin(), PI.cend());
for (auto & x: scopy)
x.delMinterm(i);
PI = std::set<Term>(scopy.cbegin(), scopy.cend());
我正在做一个布尔最小化的学校项目,在这里我想删除我的用户定义的一组元素的一些元素 class。 这是错误发生的地方:
(dc 和 PI 都是我的 class Term
的集合,通过引用传递给这个函数。std::set<Term>& dc, PI
)
for (const auto& n : dc) {
for (const auto& i : n.getMinterm()) {
m[i] = 0;
for (auto &x : PI) {
x.delMinterm(i);
}
}
}
错误信息是:
- 错误(活动)E1086 对象具有与成员函数“Term::delMinterm”不兼容的类型限定符
- 错误 C2662 'void Term::delMinterm(int)': 无法将 'this' 指针从 'const Term' 转换为 'Term &'
这是我class的内容:
class Term {
private:
int group = 0;
int literal = 0;
std::string term;
std::set<int>minterm;
bool isDontCare;
bool merged;
};
函数 delMintern(int)
只是从集合 minterm
中删除选定的元素。
Though I didn't use "const auto&" but "auto&", it still shown as a const object.
我试过去掉'&'但是它只是创建了一个本地副本,但是,我想直接修改原来的。
我也试过类似的东西:
for (auto x : PI) {
PI.erase(x);
x.delMinterm(i);
PI.insert(x);
}
但它导致了“读取访问冲突”错误。
您不能修改对 x
的引用,因为它是 const
。它是常量,因为通过循环迭代 std::set
只给出常量值。
在我的答案末尾查看带有 const_cast
示例代码的解决方案。
已知 std::set
将所有条目存储在排序树中。
现在想象一下,如果你可以在循环迭代时修改一个变量,这意味着修改后 std::set
的排序顺序可能会改变。但是 std::set
应该始终保持其树的不变性,因此它不允许进行任何修改,因此在迭代时只给出 const
值。
如果你真的需要修改集合条目,那么你必须从集合中取出它,从集合中删除,然后再次添加到集合中。即使你修改后排序没有改变,你仍然需要重新插入集合。
但是有一个 hacky 解决方法 - 您可以使您的方法 delMinentry
具有 const
修饰符。然后它修改的所有字段都应标记为 mutable
。可变字段允许从 const
方法进行修改。 std::set
允许在迭代时调用 const
方法。
还有一个变通方法——你将 delMinterm()
作为 const
方法,但在这个方法中做 const_cast<Term &>(*this).delMintermNonConst()
,换句话说,你可以从 const 方法调用非 const 方法如果你这样做 const_cast
。如果您确定要做什么,也可以直接在循环变量上执行 const 转换,换句话说,如果您以 std::set
排序顺序不变的方式修改 Term:
for (auto &x : PI) {
const_cast<Term &>(x).delMinterm(i);
}
如果 delMinterm()
导致对 Term 的这种修改,之后 std::set
的顺序可能会改变,那么您不能在上面的代码中执行 const_cast
。换句话说,如果在 delMinterm 之后你的 operator <
可能会在术语之间给出不同的结果,那么你不能做这个 const 转换,你必须重新插入到集合中(删除 Term 并再次添加)。
另外不要忘记,在重新插入 set 后,您必须从头开始重新执行 set 迭代循环,因为更改内部结构后,您无法继续迭代循环 运行,迭代器将失效。
如果 set 的顺序改变(因此你不能做 const_cast
)那么你必须重新插入 set 的值,通过将值复制到 vector,通过 delMinterm() 修改它们,复制回来设置,像这样:
std::vector<Term> scopy(PI.cbegin(), PI.cend());
for (auto & x: scopy)
x.delMinterm(i);
PI = std::set<Term>(scopy.cbegin(), scopy.cend());