考虑:
#include <stdio.h>
#include <set>
void printset(std::set<int>& Set) {
for (std::set<int>::iterator siter = Set.begin(); siter != Set.end(); ++siter) {
int val = *siter;
printf("%d ", val);
}
}
void printsetofset0(std::set<std::set<int>>& SetofSet) {
for (std::set<std::set<int>>::iterator siter = SetofSet.begin(); siter != SetofSet.end(); ++siter) {
std::set<int> Set = *siter;
printset(Set);
}
}
void printsetofset1(std::set<std::set<int>>& SetofSet) {
for (std::set<std::set<int>>::iterator siter = SetofSet.begin(); siter != SetofSet.end(); ++siter) {
printset(*siter);//this line gives error
}
}
printsetofset1
和printset(*siter);
给出错误:
<source>: In function 'void printsetofset1(std::set<std::set<int> >&)':
<source>:20:34: error: binding reference of type 'std::set<int>&' to 'const std::set<int>' discards qualifiers
20 | printset(*siter);
| ^~~~~~
<source>:4:38: note: initializing argument 1 of 'void printset(std::set<int>&)'
4 | void printset(std::set<int>& Set) {
| ~~~~~~~~~~~~~~~^~~
Compiler returned: 1
请参阅此处的Godbolt链接。
printsetofset0
与线路:std::set<int> Set = *siter; printset(Set);
编译和工作都很好。
为什么一个printsetofset0
工作,而看似功能等效(更短(的preintsetofset1
不工作?
迭代器指向的元素是常量。您可以在Notes中阅读它:因为迭代器和const_iterator都是常量迭代器(实际上可能是同一类型(,所以不可能通过这些成员函数返回的迭代器来更改容器的元素。但是,传递对printset
函数的引用将违反此属性。
在内部,集合允许通过索引结构进行快速访问。更改元素需要对集合进行重新排序(内部(。
您可以通过在printset
函数的参数中添加const
修饰符来解决这种情况:
void printset(const std::set<int>& Set)
所有打印函数都应该通过const引用获取参数,因为它们不需要修改参数。像这样:
void printset(const std::set<int>& Set)
我还建议使用基于范围的for循环来简化代码:
for (int val : Set)
printset
不能接受非常量引用的原因是,您正在将set-within-a-set传递给它,并且存储在集合中的值总是常量。有关更多信息,请参阅:为什么std::set似乎强制使用const_iterator?
问题是,尽管集合类型定义了iterator
和const_iterator
类型,但这两种类型的迭代器都为我们提供了对集合中元素的只读访问。也就是说,一个集合中的密钥是const
。我们可以使用集合迭代器读取但不能写入元素的值。
因此,要解决程序中的错误,您需要在printSet
函数的名为Set
的参数中添加低级常量,如下所示:
//------------vvvvv--------------------------->low-level const added here
void printset(const std::set<int>& Set) {
//other code as before
}
演示