4

Here's the code:

namespace Namespace
{
    struct L0
    {
        enum SomeEnum
        {
            EnumVal
        };

        struct L1
        {
            friend void f(SomeEnum)
            {
                std::cout << "f()" << std::endl;
            }
        };

        friend void g(SomeEnum)
        {
            std::cout << "g()" << std::endl;
        }
    };
}

int main()
{
    f(Namespace::L0::EnumVal); // error: f not defined
    g(Namespace::L0::EnumVal); // good
}

The idea here is to make the compiler find f() and g() through ADL.

However, this code fails to compile with gcc or clang. The similar code seemed to compile fine under MSVC though.

Maybe I miss something, but I don't really understand what is wrong with the code, and whether it is wrong at all. Would be nice if someone could shed some light on this one.

PS. Happy new year:)

dsi
  • 586
  • 3
  • 13

1 Answers1

3

SomeEnum is not a member of L1, so ADL does not find a function defined within L1.

I believe, this is a quote you were looking for:

A name first declared in a friend declaration within class or class template X becomes a member of the innermost enclosing namespace of X, but is not accessible for lookup (except argument-dependent lookup that considers X) unless a matching declaration at the namespace scope is provided - see namespaces for details.

SergeyA
  • 61,605
  • 5
  • 78
  • 137
  • Shouldn't the innermost namespace of SomeEnum also be examined? – dsi Dec 31 '15 at 18:39
  • @dsi, no, why do you think so? – SergeyA Dec 31 '15 at 18:40
  • I was relying on cppreference.com which says: "4) For arguments of enumeration type, the namespace in which the enumeration is defined is added to the set. If the enumeration type is a member of a class, that class is added to the set." – dsi Dec 31 '15 at 18:42
  • @dsi, true. But in your case, SomeEnum is NOT the member of L1. So L1 is **not** added to the set. I am not sure what confuses you. – SergeyA Dec 31 '15 at 18:43
  • I mean, for SomeEnum the namespace Namespace should be added to the set, and AFAIK the function f() is being defined in this very namespace (since it's the innermost namespace for it), so it should be found by ADL – dsi Dec 31 '15 at 18:48
  • @dsi, no. Function f() is defined in struct L1, which is defined in L0, which is defined in Namespace. Since SomeEnum is not defined in L1, no contents of L1 are considered for name resolution in your example. It is very simple. – SergeyA Dec 31 '15 at 18:50
  • function f() is defined as a friend of L1, not as a member. As a result, I thought, it should be found in its innermost namespace – dsi Dec 31 '15 at 18:54
  • @dsi, I have added the quote you were probably looking for. – SergeyA Dec 31 '15 at 18:59
  • thanks, now everything is clear. I was missing the part where it says "that considers X" – dsi Dec 31 '15 at 19:06