【问题标题】:Wrong Template Function Being Called调用了错误的模板函数
【发布时间】:2017-07-14 04:43:58
【问题描述】:

我在类似 STL 的列表容器中定义了以下两个函数:

// copy the specified VALUE some COUNT number of times and insert copies
// right before POS.
Iterator insert(Iterator pos, size_type count, const value_type 
            &value);

// copy the values from [FIRST, LAST) from the specified Iterators and
// place before POS.
template<class InputIt>
    Iterator insert(Iterator pos, InputIt first, InputIt last);

然后我尝试用一​​些任意代码测试我的函数实现:

std::list<int> stlList = { 1, 2, 3, 4, 5 };
MyList<int> intList;

intList.insert(intList.begin(), 5, 0); // expected call to first insert
intList.insert(intList.begin(), stlList.begin(), stlList.end()); // expected call to second insert

但是,对于他们俩来说,似乎正在调用第二个函数。我有点模棱两可,因为这两个函数都有三个参数,所以我看到编译器可能会调用错误的函数。但我不确定我错过了什么。我的函数基于 STL,据我所知,它们以几乎相同的方式定义它们 (STL's List Insert)。

【问题讨论】:

  • size_type 定义为什么?
  • 我认为你的size_type 是无符号的,所以模板方法是完全匹配的。您可以拨打intList.insert(intList.begin(), 5u, 0)
  • 注意关于std::list::insert的重载(4)(有两个迭代器的那个)的注释:“这个重载只有在InputIt符合InputIterator时才参与重载决议,以避免歧义与重载 (3)。"
  • 你必须使用 SFINAE。
  • @ThomasPaine 一种方法是使用std::enable_if。您需要编写一个 type_trait 来检查一个类型是否是一个迭代器(它应该具有 iterator_traits 的特化)。见this question

标签: c++ function templates


【解决方案1】:

intList.insert(intList.begin(), 5, 0);选择的原因

template<class InputIt>
Iterator insert(Iterator pos, InputIt first, InputIt last);

结束

Iterator insert(Iterator pos, size_type count, const value_type &value);

是因为模板函数产生了完全匹配。

50 具有相同的类型,因此 InputIt 被推断为 int,这使得函数看起来像

Iterator insert(Iterator pos, int first, int last);

你的其他重载是什么样子的

Iterator insert(Iterator pos, size_t first, int last);

如您所见,调用模板推导版本不需要转换,因此它优于非模板重载。

您必须将 5 强制转换为 size_t 以使其调用非模板重载或使用 SFINAE 仅在 InputIt 确实是迭代器时调用模板重载。

【讨论】:

    【解决方案2】:
    template<class InputIt>
        Iterator insert(Iterator pos, InputIt first, InputIt last);
    

    这个模板定义了一个函数,它的第二个和第三个参数是相同的类型。您在脑海中假设第二个和第三个参数必须是迭代器。但是这里没有这个要求,只是第二个和第三个参数的类型必须相同。模板参数的名称“InputIt”无关紧要。

    intList.insert(intList.begin(), 5, 0); // expected call to first insert
    

    此函数调用的第二个和第三个参数是同一类型:int。重载解决方案的另一个候选者:

    Iterator insert(Iterator pos, size_type count, const value_type 
            &value);
    

    这对于第二个和第三个参数有不同的类型。虽然这两个整数都可以在这里转换,但另一个模板函数是更好的匹配,因此它被选中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-21
      • 1970-01-01
      • 2020-10-02
      • 2017-09-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多