如何在std :: vector insert中重载模板函数选择(模式匹配)?

时间:2011-07-11 18:51:16

标签: c++ templates overloading

考虑以下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);

如何(由编译器)与最后一次重载混淆,其中1090int s和InputIterator我的类型被视为int,而不是将10作为size_type20作为const int&

现在我说“not”因为我正在实现一个向量容器(学习目的)而在我的情况下使用上面提到的调用,第三个重载是由编译器选择的而不是第二个重载因此无法编译。如果我删除第三个过载,那么事情看起来很好。

它是否与最后一个重载调用的内容有关(带迭代器特征的重载函数)?如果是这样,那么如果我假设所有迭代器都是原始指针(虽然在我的情况下我使用相同的声明,这意味着我有一个带有模板的重载#3,期望迭代器...虽然预期是错误的这里说的是因为最后它可以是任何东西,在这种情况下,它被解释为int对我来说并且无法编译)我将如何确保编译器选择正确的函数?

5 个答案:

答案 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)

在您的情况下,只要您的参数为intint,插入 就会比非模板更好地匹配模板。

标准要求它应该像无论如何选择非模板一样工作!

  

- 表格中的成员函数:

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之类的评论。

与任何标准一样,C ++ 1998/2003也有其中的错误。用这种方式看待它:你(通用你)曾经写过任何大小的完美代码,一个完美的任何文件吗?标准不是免疫的。它们是由人写的。至少有机会自动检测你编写的代码中的错误:你可以编译它,运行一些工具来对付它。你打算怎么检查标准文件?

标准由委员会制定。旧标准的一些更新是来自不同供应商的竞争非标准方案的合并。其他更新是新概念,虽然在整个标准委员会中传播,但通过桌面检查进行了验证。对我来说,令人惊讶的是,现行标准的错误与它一样少。