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?
A const iterator points to an element of constant type which means the element which is being pointed to by a const_iterator can't be modified. Though we can still update the iterator (i.e., the iterator can be incremented or decremented but the element it points to can not be changed).
The primary purpose of an iterator is to allow a user to process every element of a container while isolating the user from the internal structure of the container. This allows the container to store elements in any manner it wishes while allowing the user to treat it as if it were a simple sequence or list.
you must name the functions the same way to get the error. Changed code: https://rextester.com/SSNZ54459
And the error is
source_file.cpp: In function ‘void print_set_iter(std::set<int>::const_iterator&)’:
source_file.cpp:8:6: error: redefinition of ‘void print_set_iter(std::set<int>::const_iterator&)’
void print_set_iter(std::set<int>::const_iterator& const_it) {
^
source_file.cpp:4:6: note: ‘void print_set_iter(std::set<int>::iterator&)’ previously defined here
void print_set_iter(std::set<int>::iterator& it) {
^
There are two maybes:
If the aliased types are the same, then it is an ODR violation, same as this:
using type_1 = int;
using type_2 = int;
void func(type_1) {}
void func(type_2) {}
The aliased types are considered in the signature, not an arbitrary number of aliases that can be created for each type. The signature of the two definitions above is the same.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With