1

I refer to Stroustrup's slightly vague example in 3.3 Namespaces of 'A Tour of C++'. He gives the following example:

namespace My_Code {
    class complex { /* ... */ };  // class complex is within My_Code scope

    complex sqrt(complex); //takes our locally-defined complex as an argument

    int main(); 
}

// Defining My_Code main function *outside* of the My_Code namespace,
// but this is fine
int My_Code::main() {
    complex z {1, 2};   // My_Code::complex, or std::complex?
    auto z2 = sqrt(z);  // My_Code::sqrt(), or std::sqrt()?
    std::cout << '{' << z2.real() << ',' << z2.imag() << "}\n";
    // ...
}

int main() {
    return My_Code::main();
}

My question is: having tried this and finding that the expected types are from My_Code, why are the types of z and z2 in this case belonging to My_Code? Surely if we are defining this function outside of the namespace, then we are no longer using our own types without qualification and should be qualifying them? Or does the fact that we're implementing a function from a particular namespace explain this behaviour?

Daniel Soutar
  • 827
  • 1
  • 10
  • 24
  • look up ADL: https://stackoverflow.com/questions/8111677/what-is-argument-dependent-lookup-aka-adl-or-koenig-lookup – Quimby Oct 14 '18 at 23:27
  • 1
    Because the standard says so. For everything between `My_Code::` and the closing brace, name lookup starts in `My_Code`. Besides, you don't include any standard headers - why do you expect `std::complex` to even be declared. let alone found? – Igor Tandetnik Oct 14 '18 at 23:27
  • @IgorTandetnik I am simply quoting the example as presented in the book. In the code I used to test I `include`d the complex header. Not that it's necessary, as it transpires. – Daniel Soutar Oct 14 '18 at 23:32
  • 1
    @Quimby: ADL has nothing to do with this. – Ben Voigt Oct 15 '18 at 00:20
  • I believe `int My_Code::func() { bla }` is intended to be identical to `namespace My_Code { int func() { bla } }` – M.M Oct 15 '18 at 01:11
  • @M.M There's a difference in how names in return type are looked up (doesn't matter for `int`, of course). – Igor Tandetnik Oct 16 '18 at 00:53

2 Answers2

2

It's for consistency. Consider:

namespace N
{
    struct S
    {
         int f();
    private:
         int g();
         int x;
    };
    int h(int);

    int S::f()
    {
        // member of N::S, therefore not only finds N::S::g() during lookup
        // but has access to private member
        g();
    }
}

int N::S::g()
{
    // member of N::S, therefore finds and has access to N::S::x
    // wouldn't it be weird if it could access members of the class but
    // not its enclosing namespace?
    // therefore it also can lookup N::h()
    return h(x);
}

int N::h(int a)
{
    // member of N, therefore can lookup N::S
    //        just like N::S::g() can find N::h()
    S s;
    return a;
}

Out-of-class definitions of member functions can do lookups in the class and enclosing scopes, if the same weren't true for namespace members, then you'd have a very strange case where namespace members were visible to functions of the namespace defined outside depending on whether they were class member functions or not. That would be really confusing.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • So I suppose the way to think about out-of-class definitions and more generally out-of-namespace definitions is that we do so for reasons such as separation of representation from definition, but as far as the compiler is concerned there is no change in the scope they have access to? – Daniel Soutar Oct 15 '18 at 17:07
  • 1
    @DanielSoutar: Correct. Also, in-class definitions automatically have the `inline` keyword added, so out-of-class definitions are useful to avoid that. – Ben Voigt Oct 16 '18 at 00:39
2

As Igor Tandetnik, said because the standard says so. For everything between My_Code:: and the closing brace, name lookup starts in My_Code.

int My_Code::main() defines that your function, main, is of type int and resides inside the namespace My_Code. This implies functionality in My_Code is available to use. Therefore types z and z2 belong to My_Code.

s d
  • 584
  • 1
  • 4
  • 16