问题
I had an issue today where ADL wasn't finding a static member function for a type defined inside a class.
That is, in the below example, str(foo::Foo::Enum)
isn't located via ADL without explicitly scoping it, 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
I found this SO question, and as stated in the accepted answer, changing it to a friend
function results in ADL now working.
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
Whilst this now helps ADL, I was surprised to find that I couldn't access str
by scoping it with a namespace foo
foo::Foo::Enum e = foo::Foo::FOO1;
const char* s = foo::str(e); // error: ‘str’ is not a member of ‘foo’
I ran a test, where I printed out the result of __PRETTY_FUNCTION__
, and was even more surprised to see that the scope of str is apparently foo::
:
__PRETTY_FUNCTION__: const char* foo::str(foo::Foo::Enum)
Working example below:
#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;
}
Output:
$ ./a.out
const char* foo::str(foo::Foo::Enum)
Question:
- Why am I unable to locate
str(..)
explicitly scoping it with the enclosing namespace? - Why does
__PRETTY_FUNCTION__
say it's infoo::
, and yet I am unable to locate it as such?
回答1:
- Why am I unable to locate
str(..)
explicitly scoping it with the enclosing namespace?
From the standard, [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 ]
That means str
is not visible to name lookup; it can only be called via ADL.
- Why does
__PRETTY_FUNCTION__
say it's infoo::
, and yet I am unable to locate it as such?
From [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
does become member of namespace foo
; it's just invisible.
Explanations from 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.
来源:https://stackoverflow.com/questions/47889416/cannot-access-namespace-scope-friend-explicitly