The description of the std::set
container given by cppreference.com contains this note at the end:
The member types
iterator
andconst_iterator
may be aliases to the same type. Sinceiterator
is convertible toconst_iterator
,const_iterator
should be used in function parameter lists to avoid violations of the One Definition Rule.
I don't understand this last remark. What I understand is that a set doesn't allow modifying its elements (if you need to change one, you have to erase
it and then insert
the new one), so every iterator
works as a const_iterator
. The standard adds that it is possible (but not required) that they are the same type. So far it's clear.
What I don't get is the possible violation of the One Definition Rule. That rule says that a function can have many declarations, but only one definition. How is that violated? Let's say I have a set<int>
, and I create a function which takes as argument an iterator. Since they work the same way, I can choose its type: either set<int>::iterator
or set<int>::const_iterator
. What happens if I do not follow the advice, that is, I choose set<int>::iterator
?
I've written a program to try to find an answer. Basically there are 2 functions, one accepting an iterator
and the other accepting a const_iterator
, and I call each of them twice, once passing an iterator
and once passing a const_iterator
. Here it is:
#include <iostream>
#include <set>
void print_set_iter(std::set<int>::iterator& it) {
std::cout << "Set element from iterator: " << *it << "\n";
}
void print_set_const_iter(std::set<int>::const_iterator& const_it) {
std::cout << "Set element from const_iterator: " << *const_it << "\n";
}
int main() {
std::set<int> primes = {2, 3, 5, 7, 11};
std::set<int>::iterator it = primes.find(3);
std::set<int>::const_iterator const_it = primes.find(5);
print_set_iter(it);
print_set_iter(const_it);
print_set_const_iter(it);
print_set_const_iter(const_it);
}
I've compiled this on rextester.com using the 3 most popular compilers (gcc, clang, MSVC): there are no warnings, and it runs fine. Normally I'd expect print_set_iter(const_it);
to cause an error, but it doesn't. Does it mean that these 3 implementations are using the same type for both iterators?
But even in that case, and even if I found a compiler that doesn't use the same type for these iterators, I still don't understand why there would be an ODR violation. If the types were different, the forbidden conversion (from const to non-const) should trigger an error, but that has nothing to do with ODR. Can anyone show me an example of that violation, or explain what that note means?