考虑以下std :: vector的声明(取自cplusplus - EASTL具有相同的声明)
iterator insert ( iterator position, const T& x );
void insert ( iterator position, size_type n, const T& x );
template <class InputIterator>
void insert ( iterator position, InputIterator first, InputIterator last );
如果我输入
someVector.insert(someVector.begin(), 10, 90);
不如何(由编译器)与最后一次重载混淆,其中10
和90
是int
s和InputIterator
我的类型被视为int
,而不是将10
作为size_type
而20
作为const int&
?
现在我说“not”因为我正在实现一个向量容器(学习目的)而在我的情况下使用上面提到的调用,第三个重载是由编译器选择的而不是第二个重载因此无法编译。如果我删除第三个过载,那么事情看起来很好。
它是否与最后一个重载调用的内容有关(带迭代器特征的重载函数)?如果是这样,那么如果我假设所有迭代器都是原始指针(虽然在我的情况下我使用相同的声明,这意味着我有一个带有模板的重载#3,期望迭代器...虽然预期是错误的这里说的是因为最后它可以是任何东西,在这种情况下,它被解释为int
对我来说并且无法编译)我将如何确保编译器选择正确的函数?
答案 0 :(得分:12)
出于好奇,我看了GCC的消息来源:
template<typename _InputIterator>
void
insert(iterator __position, _InputIterator __first,
_InputIterator __last)
{
// Check whether it's an integral type. If so, it's not an iterator.
typedef typename std::__is_integer<_InputIterator>::__type _Integral;
_M_insert_dispatch(__position, __first, __last, _Integral());
}
...后来
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 438. Ambiguity in the "do the right thing" clause
template<typename _Integer>
void
_M_insert_dispatch(iterator __pos, _Integer __n, _Integer __val,
__true_type)
{ _M_fill_insert(__pos, __n, __val); }
// Called by the range insert to implement [23.1.1]/9
template<typename _InputIterator>
void
_M_insert_dispatch(iterator __pos, _InputIterator __first,
_InputIterator __last, __false_type)
{
typedef typename std::iterator_traits<_InputIterator>::
iterator_category _IterCategory;
_M_range_insert(__pos, __first, __last, _IterCategory());
}
他们似乎确实担心会出现歧义,所以明确使用typetraits和overloading来检查模板是否与整数类型匹配。
答案 1 :(得分:1)
该实现可能适用于SFINAE,在某些情况下是标准强制的,以确保InputIterator实际上是迭代器。除此之外,如果模板版本无法调用任何非模板,编译器将仅实例化模板版本。
答案 2 :(得分:1)
23.1.1 / 9规定必须选择“整数类型/值”构造函数而不是“迭代器/迭代器”构造函数,编译器必须确保它能够做出决定。
[标准文字]:
表单中的成员函数:
template <class InputIterator> // such as insert()
rt fx1(iterator p, InputIterator f, InputIterator l);
template <class InputIterator> // such as append(), assign()
rt fx2(InputIterator f, InputIterator l);
template <class InputIterator> // such as replace()
rt fx3(iterator i1, iteraror i2, InputIterator f, InputIterator l);
分别具有相同的效果:
fx1(p, static_cast<typename X::size_type>(f),
static_cast<typename X::value_type>(l));
fx2(static_cast<typename X::size_type>(f),
static_cast<typename X::value_type>(l));
fx3(i1, i2, static_cast<typename X::size_type>(f),
static_cast<typename X::value_type>(l));
如果InputIterator
是整数类型。
答案 3 :(得分:1)
在您的情况下,只要您的参数为int
和int
,插入 就会比非模板更好地匹配模板。
标准要求它应该像无论如何选择非模板一样工作!
- 表格中的成员函数:
template <class InputIterator> // such as insert()
rt fx1(iterator p, InputIterator f, InputIterator l);
template <class InputIterator> // such as append(), assign()
rt fx2(InputIterator f, InputIterator l);
template <class InputIterator> // such as replace()
rt fx3(iterator i1, iteraror i2, InputIterator f, InputIterator l);
分别具有相同的效果:
fx1(p,
static_cast<typename X::size_type>(f),
static_cast<typename X::value_type>(l));
fx2(static_cast<typename X::size_type>(f),
static_cast<typename X::value_type>(l));
fx3(i1, i2,
static_cast<typename X::size_type>(f),
static_cast<typename X::value_type>(l));
如果
InputIterator
是整数类型。
所以必须要有一些魔法来解决这个问题。
如果您将来电更改为someVector.insert(someVector.begin(), 10u, 90);
,则非模板将可能是更好的匹配,具体取决于size_type
。
答案 4 :(得分:0)
Kerrek走在正确的轨道上。 cplusplus.com的作者似乎正在寻找除gcc以外的东西。如果他们确实对gcc采取了措施,他们会发现它充满了诸如// 438. Ambiguity in the "do the right thing" clause
之类的评论。
标准由委员会制定。旧标准的一些更新是来自不同供应商的竞争非标准方案的合并。其他更新是新概念,虽然在整个标准委员会中传播,但通过桌面检查进行了验证。对我来说,令人惊讶的是,现行标准的错误与它一样少。