Consider the below code.
struct foo {
friend foo create(foo) { return {}; }
};
int main() {
auto a = create(foo{});
return 0;
}
This code compiles perfectly on all compilers.
But the next below code compiles only in MSVC.
struct foo {};
struct bar {
friend bar create(foo) { return {}; }
};
int main() {
auto a = create(foo{});
return 0;
}
Other compilers, such as gcc, clang fail to compile with the following error.
error: 'create' was not declared in this scope
9 | auto a = create(foo{});
Is this non-standard?
I'm working on some template thing, so I must declare the friend function inside of the bar.
Is there any way to achieve it?
See https://en.cppreference.com/w/cpp/language/friend
A name first declared in a friend declaration within a class or class template X becomes a member of the innermost enclosing namespace of X, but is not visible for lookup (except argument-dependent lookup that considers X) unless a matching declaration at the namespace scope is provided - see namespaces for details.
Visual studio is not complying with the standard here, your first version works as the use of foo triggers ADL.
One option is to also declare the function outside the class:
struct foo {};
struct bar {
friend bar create(foo) { return {}; }
};
bar create(foo);
int main() {
auto a = create(foo{});
return 0;
}
Solved with declaring in foo with return type auto.
It only works in C++ >= 14, but compiled in gcc >= 6.0, clang >= 8.0.
struct foo {
friend auto create(foo);
};
struct bar {
friend auto create(foo) { return bar{}; }
};
int main() {
auto a = create(foo{});
return 0;
}
Related
I have the following code I compile with C++11.
This code is a simplification of a real world usage.
namespace bar {
template<int M = 10>
struct S {
template<int N = M*2>
friend int foo(S) {
return N-M;
}
};
template<int M, int N>
int foo(S<M>);
} /* end of bar */
int main() {
bar::S<> s;
/* OK { using namespace bar; return foo<42>(s) + foo<>(s); } // */
/* NOK { return foo<42>(s) + foo<>(s); } // */
/* NOK { using namespace bar; return bar::foo<42>(s) + bar::foo<>(s); } // */
/* NOK */{ return bar::foo<42>(s) + bar::foo<>(s); } // */
}
My question is: Why does it compile with using namespace bar; with unqualified name lookup (see line with /* OK )? While it does not compile in the variant using qualified name lookup (bar::foo<>()) or unqualified name lookup without using namespace (see lines with /* NOK )?
The namespace bar contains declarations for different template functions called foo.
One is template<int M, int N> int foo(S<M>); declared at the end, and there is one for each S<M> declared as friend functions.
A friend function can only be found via ADL. So when you have bar::foo<42>(s), you could only possibly be calling the free function (Where 42 is the value of M and N can't be deduced, so it doesn't compile).
Prior to C++20, foo<42>(s) would be interpreted as foo < 42 > (s) ((foo < 42) > s with equivalent bracketing), since the < is not interpreted as a template head because lookup for foo doesn't find a template.
When you add using namespace bar;, lookup for foo finds the template function, so foo<42>(s) gets parsed as a templated function call. This eventually picks the friend function found via ADL during overload resolution.
This is fixed by adding a function template foo in the global namespace:
// Only for ADL purposes so `foo` is parsed as a template
template<typename> void foo() = delete;
int main() {
bar::S<> s;
return foo<42>(s) + foo<>(s);
}
I'm a little unsure of the verbiage to describe this problem, but take this example:
Foo.h
namespace sample {
class Foo {
public:
enum Bar {
kValue1,
kValue2,
}
Bar SomeMethod(Bar some_value);
}
} // namespace sample
Foo.cc
namespace sample {
Bar Foo::SomeMethod(Bar some_value) { // compiler complains here
if (some_value == Bar::kValue1) {
return Bar::kValue2; // but not here
} else {
return Bar::kValue1;
}
}
} // namespace sample
The compiler complains about the return type in the definition saying:
error: unknown type name 'Bar'
Why is it that giving the definition of SomeMethod the qualification Foo::SomeMethod does not extend that same qualification to the return type of Bar but does extend the qualification to all the other uses of Bar in this method definition?
Bar Foo::SomeMethod (Bar some_value)
//^^^ Here is "outside" the class ^^^ Here is "inside" the class
Since Bar is defined within the class it's required to use the Foo:: prefix to access it, unless you're inside the class itself.
It's a name lookup issue. Generally, you don't get to see inside of Foo automatically until you are in the parameter list or the function body:
namespace sample {
class Foo {
public:
enum Bar {
kValue1,
kValue2,
};
Bar SomeMethod(Bar some_value);
};
Foo::Bar Foo::SomeMethod(Bar some_value) {
if (some_value == Bar::kValue1) {
return Bar::kValue2;
} else {
return Bar::kValue1;
}
}
} //namespace sample
int main() {}
Consider this code:
class A
{
public:
void f();
private:
int foo;
};
void A::f( )
{
struct S
{
int bar = 100;
} s;
s.bar = foo;
}
This won't compile with VS2013 giving C2327 and C2065 errors on the last line. However, if we delete the initializer or put struct declaration outside this will compile. Is this a bug or standard behavior?
EDIT: Just for the question being complete here are error messages:
error C2327: 'A::foo' : is not a type name, static, or enumerator
error C2065: 'foo' : undeclared identifier
The code is fine with VS2015 RC (ultimate). So VS 2013 has a bug for in class initialization. The following code works for VS 2013
class A
{
public:
void f();
private:
int foo;
};
void A::f( )
{
struct S
{
int bar;
S(int b = 0) : bar{b} {}
} s;
s.bar = foo;
}
Your code is perfectly legal. I would guess that MSVC has a problem with the "new" (i.e. C++11) "in class initializer" int bar = 100;.
Either use a more modern compiler or, if you insist on using MSVC 2013, either write C++98 or be prepared to get random compilation errors for correct code.
Give this a shot.
class A
{
public:
void f();
private:
int foo;
};
void A::f( )
{
struct S
{
int bar;
S() { bar = 100; }
} s;
s.bar = foo;
}
EDIT: Just an FYI, you're trying to initialize a non-const static member in a local class.
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;
}
friend works on a declaration, not a definition.
struct foo
{
friend foo f();
};
foo f() { return {}; }
int main()
{
auto x = f();
return 0;
}
compiles
I got this example from my book, but I have no idea how to actually call the ticket function. This is the code:
#include <iostream>
class Manager {
public:
template<typename T>
friend int ticket() {
return ++Manager::counter;
}
static int counter;
};
int main()
{
Manager m;
std::cout << "ticket: " << ticket<int>() << std::endl;
}
I get the "candidate function(s) not accessible" error message.
A few points will help you figure out what's going on here:
I) Friend function definitions within classes can only be found by Argument dependent lookup when called from outside the class definition.
II) Function templates that are supplied explicit template arguments do not undergo ADL unless the compiler is given some explicit help in identifying the call as a function call.
III) Argument dependent lookup (ADL) only works for user defined types.
A few examples will better illustrate each of the above points:
//------------------------
struct S
{
friend int f(int) { return 0; } // 1
friend int f(S) { return 0; } // 2
};
S s;
int i = f(3); // error - ADL does not work for ints, (III)
int j = f(s); // ok - ADL works for UDTs and helps find friend function - calls 2 (III)
// so how do we call function 1? If the compiler won't find the name via ADL
// declare the function in the namespace scope (since that is where the friend function
// gets injected)
int f(int); // This function declaration refers to the same function as #1
int k = f(3); // ok - but not because of ADL
// ok now lets add some friend templates and make this interesting
struct S
{
friend int f(int) { return 0; } // 1
friend int f(S) { return 0; } // 2
template<class T> friend int g(int) { return 0; } // 3
template<class T> friend int g(S) { return 0; } // 4
template<class T> friend int g() { return 0; } // 5
};
S s;
int k = g(5); // error - no ADL (III)
int l = g(s); // ok - ADL - calls 4
int m = g<int>(s); // should call 4 - but no ADL (point II above)
// ok so point II above says we have to give the compiler some help here
// We have to tell the compiler that g<int> identifies a function
// The way to do that is to add a visible dummy template function declaration
template<class /*Dummy*/, class /*TriggerADL*/> void g();
int m = g<int>(s); // ok - compiler recognizes fun call, ADL triggered - calls 4
int n = g<int>(3); // still not ok - no ADL for ints
// so how do we call either function 3 or 5 since we cannot rely on ADL?
// Remember friend functions are injected into the outer namespace
// so lets just declare the functions in the outer namespace (as we did above)
// both these declarations of g below refer to their counterparts defined in S
template<class T> int g(int);
template<class T> int g();
int o = g<int>(3); // ok
int p = g<int>(); // ok
// Of course once you have these two declarations at namespace scope
// you can get rid of the Dummy, TriggerADL declaration.
Ok so now lets return to the Vandevoorde example that you quoted, and now this should be easy:
#include <iostream>
class Manager {
public:
template<typename T>
friend int ticket() {
return ++Manager::counter;
}
static int counter;
};
int Manager::counter;
template<class T> int ticket(); // <-- this should work with a conformant compiler
int main()
{
Manager m;
std::cout << "ticket: " << ticket<int>() << std::endl;
}
Hope that helps :)
Hotfix
There is a hot-fix available, but read the below explanation if you want to understand what's going on.
#include <iostream>
template<typename T> int ticket();
class Manager {
public:
template<typename T>
friend int ticket() {
return ++Manager::counter;
}
static int counter;
};
int Manager::counter; // don't forget the definition
int main() {
Manager m;
std::cout << "ticket: " << ticket<int>() << std::endl;
}
As the snippet shows, you have to declare the template to make it visible when you call it.
Friend function definitions
This is confusing, since there are some rules in the way in this case. Some basic points, and then some other points.
struct A {
friend void f(A*) { std::cout << "hello"; }
};
What does it do? It defines a friend function. Such a function is a member of the enclosing namespace. It's not a class member, even though it is defined within a class! The fact that it's defined within a class only changes the lexical scope of that function: It can refer to that class' members directly, without preceding the class-name.
Most importantly, though, the function is not visible after being declared. You cannot take its address doing something like this, for example
&f
The only way that the function would work is using argument dependent lookup. A lookup that ends up having that class as its associated class will consider that friend function. That means that the following works:
f((A*)0);
It works because the call includes an argument with type that has the class included. In that case, the class is an associated class, and the friend declaration will be considered.
The following won't work, for example
f(0);
Because it has no idea that it should look within A to find a friend declaration. A friend function definition of a function without an argument won't be found, because there is no argument dependent lookup happening, then.
Friend function definition for templates
In addition to the fact that your call does not include arguments, it has another problem. If you define a friend function template, the matter is more complicated. There is a rule that says that if the compiler sees T<A1, A2, A3>, that this only refers to a template specialization if T actually resolves to a template. Consider
ticket < int > ()
The compiler can't resolve ticket, because it is not visible to normal lookup. Therefor, the rule says that ticket<int> does not refer to a function. It has to be parsed as a relational expression, yielding to the following
(ticket < int) > ()
That will be a syntax error, because int is not a value, and () is neither a value.
Example
Here is an example where it matters.
struct A {
template<int I> friend void f(A*) { }
};
// try to comment this out
template<typename Dummy> void f();
int main() {
f<1>((A*)0);
}
That compiles. It compiles because f resolves to a template (although a completely different one that can't even accept a non-type template argument - but that doesn't matter!). But a Standard conforming compiler will not compile the snippet once you comment out the second declaration, because it's compiled as a relational expression (less-than and smaller-than) and it will not find symbol f.
Read this thread for further information: What am I missing in this template toy example?.
I do get the same error using the MS VS++ compiler. According to the docs on MSDN:
http://msdn.microsoft.com/en-us/library/h2x4fzdz(VS.80).aspx
Friends are not in the class's scope,
and they are not called using the
member-selection operators (. and –>)
unless they are members of another
class. A friend function is declared
by the class that is granting access.
So friend functions are not actually part of the class and should therefore not be defined in class scope. Define the function outside of the class:
#include <iostream>
class Manager {
public:
template<typename T>
friend int ticket();
static int counter;
};
template<typename T>
int ticket() {
return ++Manager::counter;
}
int Manager::counter;
int main()
{
Manager m;
std::cout << "ticket: " << ticket<int>() << std::endl;
}
Why not make it static instead?
#include <iostream>
class Manager {
public:
template<typename T>
static int ticket()
{
return ++Manager::counter;
}
static int counter;
};
int main()
{
Manager m;
std::cout << "ticket: " << Manager::ticket<int>() << std::endl;
}
Though really, it doesn't have to be a template either. I assume you needed information specifically about friend templates?