使用不带前缀“std”且不带“using namespace std;”的 std::sort()编译成功

Posted

技术标签:

【中文标题】使用不带前缀“std”且不带“using namespace std;”的 std::sort()编译成功【英文标题】:Using std::sort() without prefix "std" and also without "using namespace std;" compiles successfully 【发布时间】:2017-01-05 18:19:57 【问题描述】:

由于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());

ideone.com

但是这段代码没有。

#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 标志。

从这两个代码 sn-ps 可以清楚地看出std::vector 与此有关。但我无法弄清楚。

【问题讨论】:

我正在考虑依赖于参数的查找。 请注意,第二个示例使用 MSVC 编译,因为它为 std::array 提供了自定义迭代器。 【参考方案1】:

这是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 在 cmets 中的帮助,我们看到这些类型是 __gnu_cxx::__normal_iterator&lt;int*, std::vector&lt;int, std::allocator&lt;int&gt; &gt; &gt;int*

对于向量,在通常的名称查找失败后,编译器会在 __gnu_cxxstd 命名空间中搜索 sort 函数,__gnu_cxx 因为它是 __gnu_cxx::normal_iteratorstd 的命名空间,因为它是模板参数之一的命名空间std::vector&lt;int, std::allocator&lt;int&gt; &gt;。它找到std::sort

对于std::array,迭代器只是int*s,因此依赖于参数的查找不会搜索其他命名空间,也找不到sort 函数。

【讨论】:

我不完全确定如何阅读”。它是__gnu_cxx::__normal_iterator&lt;int*, std::vector&lt;int, std::allocator&lt;int&gt; &gt; &gt;int*。并不是说它有多大帮助...... @Revolver_Ocelot 不同的命名空间。 sort 可能是在 __gnu_cxx 中定义的。 哦,等等,它正在查找模板参数的命名空间。 Here 获取类型的另一种方式(在错误消息中)。 相关:使用 MSVC,迭代器类型改为 V?$_Vector_iterator@V?$_Vector_val@HV?$allocator@H@std@@@std@@@std@@ (class std::_Vector_iterator&lt;class std::_Vector_val&lt;int,class std::allocator&lt;int&gt; &gt; &gt;) 和 V?$_Array_iterator@H$04@std@@ (class std::_Array_iterator&lt;int,5&gt;);由于std::array 使用了自定义迭代器,因此启用了 ADL。【参考方案2】:

这是依赖于参数的查找。根据 Stroustroup 的The C++ Programming Language: 4th Edition,这里有两条适用的规则:

1) 如果参数是命名空间的成员,则关联的命名空间 是封闭的命名空间。

2) 如果参数是内置类型,则没有关联的命名空间。

在您的第一种和第二种情况下,begin() 和 end() 返回迭代器。但是,C++ 标准将迭代器定义为任何类型的任何变量,可以在其上执行迭代操作。 (换句话说,迭代器是一个通过模板强制执行的设计概念。)

根据另一个答案,第一种情况下的迭代器是与 sort() 属于同一命名空间的数据类型的变量。但是,第二种情况下的迭代器具有原始数据类型。根据规则 #2,这些迭代器没有关联的命名空间。

【讨论】:

解释,为什么它在第一种情况下有效而在第二种情况下无效,这会使答案更好。 预期每个返回迭代器 - 即“迭代器”类型的变量”。不,他们应该返回一些符合 RandomAccessIterator 概念的东西。原始指针确实遵循该概念。

以上是关于使用不带前缀“std”且不带“using namespace std;”的 std::sort()编译成功的主要内容,如果未能解决你的问题,请参考以下文章

带有矩形角且不带箭头的popover presentviewcontroller

将 s3 文件复制到带有 IDENTITY 列且不带 EXPLICIT_IDS 的 Redshift 表

Onclick 显示/隐藏仅 div 且不带 href 的 css。没有jQuery

Libtool 为对象添加前缀,但 gcov 要求它们不带前缀

else是和之前与其最近的且不带else的if配对,有种情况我不太明白

如何在 Sequelize ORM 中获取不带前缀表名的连接数据结果