简体   繁体   English

为什么传递给函数set :: iterator而不是const_iterator违反了One Definition Rule?

[英]Why does passing to a function a set::iterator instead of a const_iterator violate the One Definition Rule?

The description of the std::set container given by cppreference.com contains this note at the end: cppreference.com给出std::set容器的描述最后包含这个注释:

The member types iterator and const_iterator may be aliases to the same type. 成员类型iteratorconst_iterator可以是同一类型的别名。 Since iterator is convertible to const_iterator , const_iterator should be used in function parameter lists to avoid violations of the One Definition Rule. 由于iterator可以转换为const_iterator ,因此应在函数参数列表中使用const_iterator以避免违反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 . 我理解的是一个集合不允许修改它的元素(如果你需要更改它,你必须erase它然后insert新的const_iterator ),所以每个iterator作为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. 假设我有一个set<int> ,我创建了一个函数,它将迭代器作为参数。 Since they work the same way, I can choose its type: either set<int>::iterator or set<int>::const_iterator . 由于它们以相同的方式工作,我可以选择它的类型: set<int>::iteratorset<int>::const_iterator What happens if I do not follow the advice, that is, I choose set<int>::iterator ? 如果我遵循建议会发生什么,也就是说,我选择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 . 基本上有两个函数,一个接受一个iterator ,另一个接受一个const_iterator ,我调用它们两次,一次传递一个iterator ,一次传递一个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. 我使用3个最受欢迎的编译器(gcc,clang,MSVC)在rextester.com上编译了这个:没有警告,它运行正常。 Normally I'd expect print_set_iter(const_it); 通常我会期望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. 但即使在这种情况下,即使我发现编译器不对这些迭代器使用相同的类型,我仍然不明白为什么会出现ODR违规。 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. 如果类型不同,禁止转换(从const到非const)应该触发错误,但这与ODR无关。 Can anyone show me an example of that violation, or explain what that note means? 任何人都可以向我展示这种违规行为的例子,或者解释一下该注释的含义吗?

There are two maybes : 有两种maybes:

If the aliased types are the same, then it is an ODR violation, same as this: 如果别名类型相同,那么它是ODR违规,与此相同:

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. 上面两个定义的签名是相同的。

you must name the functions the same way to get the error. 您必须以相同的方式命名函数以获取错误。 Changed code: https://rextester.com/SSNZ54459 更改的代码: 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) {
      ^

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM