I attempted to get friend name injection to work with the following snippet:
struct foo
{
friend foo f() { return {}; }
};
int main()
{
auto x = f();
return 0;
}
This fails to compile:
test.cc:8:10: error: use of undeclared identifier 'f'
auto x = f();
^
1 error generated.
I have to declare f
in the outer namespace for the error to vanish.
The standard has an explanation in paragraph 3 of §7.3.1.2:
If a friend declaration in a non-local class first declares a class, function, class template or function template97 the friend is a member of the innermost enclosing namespace. The friend declaration does not by itself make the name visible to unqualified lookup (3.4.1) or qualified lookup (3.4.3). [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 ]
My question: why do we need an extra declaration of f
at namespace scope for this to compile? Does it have to do with ADL? Is there a (hacky) way around this requirement?
You can force ADL:
struct foo {
friend foo f(foo *) { return {}; }
};
int main()
{
auto x = f((foo *) 0);
return 0;
}
Compiles with g++ 4.9.0 and clang++ 3.4. Of course, might not be practical.
ADDENDUM: Thanks to Richard Hodges, here is another possible workaround, but it might be a g++ 4.9.0 bug. There are differences between clang++ and g++. I'll try to look into what the standard says, if I have time. If the OP wants to post this as a new question asking about which compiler is wrong, please do.
struct foo {
friend foo f1() { return {}; }
friend foo f2(foo *) { return {}; }
template<typename T = void>
friend foo f3() { return {}; }
};
int main()
{
auto x1 = f1(); // Error, f1() not visible.
auto x2 = f2((foo *) 0); // Force ADL.
auto x3 = f3<void>(); // Use template, okay with g++, fails with clang++.
auto x4 = f3(); // Use template with default param, okay with g++, fails with clang++.
return 0;
}