使用不带前缀 "std" 且不带 "using namespace std;" 的 std::sort() 编译成功
Using std::sort() without prefix "std" and also without "using namespace std;" compiles successfully
由于 sort()
在 namespace std
中定义,因此必须始终用作 std::sort
。但即使没有 std
,以下代码也能正确编译。
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> nums = {4,3,1,7,2,0};
sort(nums.begin(),nums.end());
}
但是这段代码没有。
#include <array>
#include <algorithm>
int main()
{
std::array<int,5> nums = {4,1,8,9,6};
sort(nums.begin(),nums.end());
}
使用 gcc 4.8.4
并启用 -std=c++11
标志。
从这两个代码片段中可以清楚地看出,std::vector
与 this.But 有关,我无法弄清楚。
这是依赖于参数的查找。根据 Stroustroup 的 C++ 编程语言:第 4 版,这里有两条规则适用:
1) If an argument is a member of a namespace, the associated namespaces
are the enclosing namespaces.
2) If an argument is a built-in type, there are no associated namespaces.
在第一种和第二种情况下,begin() 和 end() return 迭代器。但是,C++ 标准将迭代器定义为任何类型的任何变量,可以对其执行迭代操作。 (换句话说,迭代器是一种通过 模板 强制执行的设计概念。)
根据另一个答案,第一种情况下的迭代器是数据类型的变量,属于与 sort() 相同的命名空间。但是,第二种情况下的迭代器具有原始数据类型。根据规则 #2,这些迭代器没有关联的命名空间。
这是argument-dependent lookup。如果使用typeid
检查涉及的迭代器类型:
#include <iostream>
#include <typeinfo>
#include <vector>
#include <array>
int main() {
std::cout << typeid(std::vector<int>::iterator).name() << '\n';
std::cout << typeid(std::array<int, 5>::iterator).name() << std::endl;
return 0;
}
至少在 Ideone,您会得到以下输出:
N9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEE
Pi
在Revolver_Ocelot的帮助下,我们看到这些类型是__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >
和int*
。
对于向量,在通常的名称查找失败后,编译器会在 __gnu_cxx
和 std
命名空间中搜索 sort
函数,__gnu_cxx
因为它是命名空间__gnu_cxx::normal_iterator
和 std
的名称空间,因为它是模板参数之一 std::vector<int, std::allocator<int> >
的命名空间。它找到 std::sort
.
对于 std::array
,迭代器只是 int*
,因此依赖于参数的查找不会搜索其他名称空间,也不会找到 sort
函数。
由于 sort()
在 namespace std
中定义,因此必须始终用作 std::sort
。但即使没有 std
,以下代码也能正确编译。
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> nums = {4,3,1,7,2,0};
sort(nums.begin(),nums.end());
}
但是这段代码没有。
#include <array>
#include <algorithm>
int main()
{
std::array<int,5> nums = {4,1,8,9,6};
sort(nums.begin(),nums.end());
}
使用 gcc 4.8.4
并启用 -std=c++11
标志。
从这两个代码片段中可以清楚地看出,std::vector
与 this.But 有关,我无法弄清楚。
这是依赖于参数的查找。根据 Stroustroup 的 C++ 编程语言:第 4 版,这里有两条规则适用:
1) If an argument is a member of a namespace, the associated namespaces are the enclosing namespaces.
2) If an argument is a built-in type, there are no associated namespaces.
在第一种和第二种情况下,begin() 和 end() return 迭代器。但是,C++ 标准将迭代器定义为任何类型的任何变量,可以对其执行迭代操作。 (换句话说,迭代器是一种通过 模板 强制执行的设计概念。)
根据另一个答案,第一种情况下的迭代器是数据类型的变量,属于与 sort() 相同的命名空间。但是,第二种情况下的迭代器具有原始数据类型。根据规则 #2,这些迭代器没有关联的命名空间。
这是argument-dependent lookup。如果使用typeid
检查涉及的迭代器类型:
#include <iostream>
#include <typeinfo>
#include <vector>
#include <array>
int main() {
std::cout << typeid(std::vector<int>::iterator).name() << '\n';
std::cout << typeid(std::array<int, 5>::iterator).name() << std::endl;
return 0;
}
至少在 Ideone,您会得到以下输出:
N9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEE
Pi
在Revolver_Ocelot的帮助下,我们看到这些类型是__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >
和int*
。
对于向量,在通常的名称查找失败后,编译器会在 __gnu_cxx
和 std
命名空间中搜索 sort
函数,__gnu_cxx
因为它是命名空间__gnu_cxx::normal_iterator
和 std
的名称空间,因为它是模板参数之一 std::vector<int, std::allocator<int> >
的命名空间。它找到 std::sort
.
对于 std::array
,迭代器只是 int*
,因此依赖于参数的查找不会搜索其他名称空间,也不会找到 sort
函数。