3

I noticed that begin (without namespace specifier) compiles in some situations and fails in others.

Can you guys explain why can it work when it works and why is there a difference due to the use cases?

The code fails to compile the same way under VS2017 15.9.7 and gcc-8.3.0 std=c++14 is used for both. vs: error C3861: 'begin': identifier not found gcc: error: ‘begin’ was not declared in this scope

#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
    }
}

I expected that begin without the std:: would never work because it's declared in std namespace and no one says using namespace std or using begin. (or if anyone did then there wouldn't be any error)

I debugged into the first two lines marked as 'works' and I saw that it jumps into the same std::begin implementation as one line before.

P.W
  • 26,289
  • 6
  • 39
  • 76
xropi
  • 43
  • 4

1 Answers1

1

The statements marked "works" work because the arguments passed to begin belong to the same namespace as begin.

In the below example:

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

The type of the argument arr belongs to the namespace std::. The begin also belongs to the namespace std.

To find begin the compiler does not just look at local scope, but also the namespaces that contain the argument's type. This is called Argument Dependent Lookup. And when the compiler looks at the std namespace, it finds begin and is able to call it.

The case is the same when the type of the argument is std::pair

However, in the statements marked "error", the type of the arguments passed to begin are a C-style array and a Struct. And both of these do not belong to the std namespace. So the compiler cannot find begin and therefore cannot call it.

P.W
  • 26,289
  • 6
  • 39
  • 76