无法显式访问命名空间范围友元

cannot access namespace scope friend explicitly

我今天遇到一个问题,ADL 没有为 class 中定义的类型找到静态成员函数。

也就是说,在下面的例子中,str(foo::Foo::Enum) 不是通过 ADL 定位的,而没有明确地确定它的范围,foo::Foo::str(foo::Foo::Enum)

namespace foo {

struct Foo
{
    enum Enum
    {
        FOO1,
        FOO2
    };

    static const char* str(Enum e);
};

}

foo::Foo::Enum e = foo::Foo::FOO1;
const char* s = str(e);              // ADL doesn't work

我发现 this SO 问题,并且如已接受的答案中所述,将其更改为 friend 函数会导致 ADL 现在工作。

namespace foo {

struct Foo
{
    enum Enum
    {
        FOO1,
        FOO2
    };

    friend const char* str(Enum e);  // note str is now a friend
};

}

foo::Foo::Enum e = foo::Foo::FOO1;
const char* s = str(e);              // ADL works now

虽然这现在有助于 ADL,但我惊讶地发现我无法通过使用命名空间 foo

来访问 str
foo::Foo::Enum e = foo::Foo::FOO1;
const char* s = foo::str(e);         // error: ‘str’ is not a member of ‘foo’

我 运行 一个测试,我打印了 __PRETTY_FUNCTION__ 的结果,更惊讶地看到 str 的范围显然是 foo:::

__PRETTY_FUNCTION__: const char* foo::str(foo::Foo::Enum)

下面的工作示例:

#include <iostream>

namespace foo {

struct Foo
{
    enum Enum
    {
        FOO1,
        FOO2
    };

    friend const char* str(Enum e)
    {
        return __PRETTY_FUNCTION__;
    }
};

}

int main()
{
    foo::Foo::Enum e = foo::Foo::FOO1;

    std::cout << str(e) << '\n';
    // std::cout << foo::str(e) << '\n'; // error: ‘str’ is not a member of ‘foo’

    return 0;
}

输出:

$ ./a.out
const char* foo::str(foo::Foo::Enum)

问题:

  • Why am I unable to locate str(..) explicitly scoping it with the enclosing namespace?

根据标准,[namespace.memdef]/3

If a friend declaration in a non-local class first declares a class, function, class template or function template the friend is a member of the innermost enclosing namespace. The friend declaration does not by itself make the name visible to unqualified lookup or qualified lookup. [ Note: The name of the friend will be visible in its namespace if a matching declaration is provided at namespace scope (either before or after the class definition granting friendship). — end note ]

这意味着 str 对名称查找不可见;它只能通过 ADL 调用。

  • Why does __PRETTY_FUNCTION__ say it's in foo::, and yet I am unable to locate it as such?

来自 [class.friend]/6,

A function can be defined in a friend declaration of a class if and only if the class is a non-local class ([class.local]), the function name is unqualified, and the function has namespace scope.

str 确实成为命名空间 foo 的成员;它只是看不见。

来自cppreference.com的解释:

Names introduced by friend declarations within a non-local class X become members of the innermost enclosing namespace of X, but they do not become visible to lookup (neither unqualified nor qualified) unless a matching declaration is provided at namespace scope, either before or after the class definition. Such name may be found through ADL which considers both namespaces and classes.