为什么 free 函数 begin 不能在 C 数组上运行,而 std::begin 在某些情况下可以在 C++14 中运行?

Why can't the free function begin operate on C arrays while std::begin can in C++14 in some cases?

我注意到 begin(不带命名空间说明符)在某些情况下可以编译,而在其他情况下会失败。

你们能解释一下为什么它可以在工作时工作以及为什么会因用例而有所不同吗?

代码在VS2017 15.9.7和gcc-8.3.0下同样编译失败 std=c++14 用于两者。 vs: error C3861: 'begin': 找不到标识符 gcc: 错误: ‘begin’ 未在此范围内声明

#include <array>

struct Struct {
    int x;
};

int main()
{
    {
        std::array<int, 4> arr;
        std::begin(arr);
        begin(arr);     // works, calls the same as std::begin above
    }

    {
        std::pair<int, int> arr[4];
        std::begin(arr);
        begin(arr);     // works, calls the same as std::begin above
    }

    {
        int arr[4];
        std::begin(arr);
        begin(arr);     // error
    }

    {
        Struct arr[4];
        std::begin(arr);
        begin(arr);     // error
    }
}

我预计没有 std:: 的 begin 将永远无法工作,因为它是在 std 命名空间中声明的,而且没有人说使用命名空间 std 或使用 begin。 (或者如果有人做了那么就不会有任何错误)

我调试了标记为 'works' 的前两行,我看到它跳转到与前一行相同的 std::begin 实现。

标记为 "works" 的语句有效,因为传递给 begin 的参数属于与 begin 相同的命名空间。

在下面的例子中:

std::array<int, 4> arr;
begin(arr);     // works, calls the same as std::begin above

参数类型 arr 属于命名空间 std::begin 也属于命名空间 std

为了找到 begin,编译器不仅会查看本地范围,还会查看包含参数类型的命名空间。这叫做Argument Dependent Lookup。当编译器查看 std 命名空间时,它会找到 begin 并能够调用它。

参数类型为std::pair

情况相同

然而,在标记为 "error" 的语句中,传递给 begin 的参数类型是 C-style 数组和 Struct。而且这两个都不属于 std 命名空间。所以编译器无法找到 begin,因此无法调用它。