繁体   English   中英

原始 int 指针与 vector::iterator<int>

[英]Raw int pointer vs vector::iterator<int>

我试图了解原始指针和向量迭代器之间的区别。 然而,下面的程序让我失望了。 模板函数是否优先于非模板函数?

预期:您好! 世界!
实际:你好! 你好!

#include <bits/stdc++.h>
using namespace std;

template<typename It>
void foo(It begin, It end) {
  cout << "hello! ";
}

void foo(const int* a, const int* b, size_t n=0) {
  cout << "world! ";
}

int main() {
  vector<int> A = {5,6,7,8,9};
  int B[] = {1,2,3,4,5};
      
  foo(A.begin(), A.end());
  foo(B, B+5);

  cout << endl;
}

一般来说,类模板std::vector的迭代器不是指针(尽管在一些早期版本的编译器中它们被实现为指针)。

对于这两个调用,都将调用模板函数。 非模板函数的调用需要转换成const(限定转换)。

如果数组是用限定符 const 声明的,则将调用非模板函数,例如

const int B[] = {1,2,3,4,5};

另一方面,如果您将使用限定符 const 声明向量,例如

const vector<int> A = {5,6,7,8,9};

然而,模板函数将被调用,因为将使用std::vector<int>::const_iterator类型的对象,这些对象不是指向常量对象的指针。

iterator是一组在 STL 的各种容器中使用的类。 拥有此范例可确保您可以在容器为模板的模板中使用迭代器

template<typename Container> is_alone(const Container& c) {
    Container::iterator i = c.begin();
    if(i == c.end())  {
        return false;
    }
    ++i;
    return i == c.end();
}

无论 Container 是std::vectorstd::unordered_mapstd::set ,上面的这个片段都可以工作……迭代器如何访问容器的成员是由植入定义的。 具体而言, std::vector<T>::iterator几乎总是使用指针来实现,但是这对std::vector<T>::iterator的用户是隐藏的,它只需要知道迭代器可以是高级的,并且可以使用operator*访问。

对于您的代码片段,C++ 编译器将始终使用与您调用的具体参数类型匹配的最专业的参数类型来定位函数。 这里是int* ,所以通过设置It = int*调用模板,比用const int*调用函数更专业,所以首选模板。

让我们根据具体情况考虑正在发生的事情。

情况1

这里我们考虑调用:

foo(A.begin(), A.end());

这里调用表达式的参数A.begin()A.end()std::vector::iterator类型,但非模板函数的参数abconst int*类型。 现在,由于参数类型std::vector::iterator到参数类型const int*之间没有隐式转换,因此非模板函数甚至不适用于此调用。

因此,模板函数可以与推导出为std::vector::iterator的参数一起使用。 因此我们得到了第一个hello! 在输出中。


案例2

这里我们考虑调用:

foo(B, B+5);

在这种情况下,两个参数都是int*类型(因为数组衰减为指向它们的第一个元素的指针)。

现在,这里有两个可行的候选人

第一个候选者是具有const int*类型的参数ab的非模板函数。 但请注意,要使用此非模板函数,需要进行限定转换(从int*const int* )。

第二个候选者是从函数模板生成的函数foo<int *>(int *, int *) ,其中参数被推导出为int*

所以我们有两个候选人。 但如上所述,第一个候选者需要转换,而第二个候选者(从函数模板生成)不需要从参数类型到参数类型的任何转换。 因此,第二个候选人比第一个候选人更受欢迎,我们得到了第二个hello! 在输出中。


边注

如果您要将非模板函数的参数类型更改为int* ,那么非模板函数将优于从函数模板生成的函数,在这种情况下,您将得到world! 作为调用foo(B, B+4)的输出。

template<typename It> //#1
void foo(It begin, It end) {
  cout << "hello! ";
}
//-------vvv-----vvv----------------------->changed to int* 
void foo(int* a, int* b, size_t n=0) {//#2
  cout << "world! ";
}

int main() {
  vector<int> A = {5,6,7,8,9};
  int B[] = {1,2,3,4,5};
      
  foo(A.begin(), A.end()); //calls #1 
  foo(B, B+4);             //calls #2
 
  cout << endl;
}

暂无
暂无

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

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