Please read the code to know the problem :
#include <iostream>
void fun(int value)
{
//starts local class definition
class test
{
int x;
public:
test(int a) : x(a) {}
void display() const
{
std::cout << "x = " << x << std::endl;
}
};
//end of the definition
test t1(value);
t1.display();
//if we write the statement t1.x=100; here .It will give us an error
//because we can not access the private members from the enclosing function
//now what should I do if I want to access the private members of the test class from fun function
}
int main()
{
fun(5);
}
Should I make the fun function as friend for the local class(test). I was reading a book and there was said that we can achieve this by declaring the enclosing function as a friend. Now my problem is this I don't know how to make the enclosing function as a friend of the local class. Please, someone tell me how can I do so.
clangs accepts friend void ::fun(int);:
void fun(int value)
{
//starts local class definition
class test
{
friend void ::fun(int);
int x;
public:
test(int a)
{
x=a;
}
void display()
{
std::cout << "x = " << x << std::endl;
}
};
//end of the definition
test t1(value);
t1.display();
t1.x = 42;
t1.display();
}
Demo
Whereas g++ rejects it.
Not sure which compiler is right though.
Should I make the fun function as friend for the local class(test)
It's unclear whether you should. It is often a good idea to avoid breaking the encapsulation that private members offer. Or conversely, if the encapsulation isn't needed, then maybe it would be simpler for the member to be public. But let's instead consider whether you could...
Standard says (quoting latest draft):
[class.friend]
If a friend declaration appears in a local class ([class.local]) and the name specified is an unqualified name, a prior declaration is looked up without considering scopes that are outside the innermost enclosing non-class scope.
For a friend function declaration, if there is no prior declaration, the program is ill-formed. ...
If I interpret this legalese correctly, no unqualified name outside of the function body of fun can be looked up. As far as I know, the declaration of fun itself is outside of that scope. However also as far as I know, nothing should prevent you from re-declaring the function:
void fun(int value)
{
void fun(int); // (re)declaration within innermost enclosing non-class scope
class test
{
friend void fun(int); // the friend declaration
This appears to work in Clang and MSVC, but not in GCC unfortunately, which still doesn't allow access to the private member. This may be a GCC bug.
Another option would be to declare the friend with a qualified name:
class test
{
friend void ::fun(int); // qualified name
In which case the restriction above wouldn't apply. Unfortunately, GCC doesn't accept this either, and without the local re-declaration produces a diagnostic:
error: friend declaration 'void fun(int)' in local class without prior local declaration
This looks like a separate bug, which reproduces whether declaring ::fun or any other qualified function name as friend. I found an existing bugreport: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69410
First declare the function
void fun(int);
Then in class :
public:
friend void ::fun(int );
Related
I'm trying to compile a program which was written with super modern arcane coding techniques. These techniques are so advanced that GCC and Clang work but Visual Studio 2017 throws an error. Now I'm wondering whether Visual Studio got it right.
Consider the following program:
#include <functional>
#include <iostream>
class A
{
public:
A(int i) : foo(i) { }
private:
int foo;
friend class B;
};
class B
{
public:
void printFooFromA(const A& a, std::function<void (const A&)> printer = [](const A& a) {
std::cout << "a.foo is " << a.foo << std::endl;
}) {
printer(a);
}
};
int main()
{
A a(123);
B b;
b.printFooFromA(a);
return 0;
}
Visual Studio throws Error C2248:'A::foo': cannot access private member declared in class 'A'.
The root of the error is in the declaration for printFooFromA: The "printer" argument is given a default value in the form of a lambda. Inside the lambda, it accesses A::foo. Since foo is private, it can only be accessed within A or a friend of A.
Whether this is an error or not hinges on if the lambda should be considered a friend of A. Visual Studio says no while GCC says yes. Does the C++ standard specify this?
Edited to add: There are existing questions on StackOverflow concerning whether a lambda is considered a friend of a class, but none of those questions address the case where a lambda is in default argument position and whether this complies with standard C++.
According to C++17 [class.friend]/2:
Declaring a class to be a friend implies that the names of private and protected members from the class granting friendship can be accessed in the base-specifiers and member declarations of the befriended class.
Declaring a class member function is certainly a member declaration, and the lambda is certainly in the declaration, so I would interpret this as saying that the lambda has friendship status.
To back this up, there is [expr.prim.lambda.closure]/2:
The closure type is declared in the smallest block scope, class scope, or namespace scope that contains the corresponding lambda-expression. [Note: This determines the set of namespaces and classes associated with the closure type.]
So the closure type of the lambda is declared in B's scope, meaning that B is roughly equivalent to:
class B
{
struct lam
{
void operator()(const A& a)
{
std::cout << "a.foo is " << a.foo << std::endl;
}
};
public:
void printFooFromA(const A& a, std::function<void (const A&)> printer = lam())
{
printer(a);
}
};
In [class.friend]/2 it gives an example with this same layout, showing that friend class X; means that nested classes of X are also friends.
It seems clear that this is therefore a bug in MSVC.
Consider the following code:
#include <iostream>
struct foo {
friend void bar(foo) {}
void foobar() {
std::cout << &bar << '\n'; // error
}
};
int main() {
bar(foo{}); // ok, visible through ADL
foo{}.foobar();
}
gcc gives me this error:
main.cpp: In member function 'void foo::foobar()':
main.cpp:7:23: error: 'bar' was not declared in this scope
std::cout << &bar << '\n'; // error
^~~
That's because bar is a friend function defined in the class itself, making it invisible in the global namespace. The only way to access it is through ADL, but I have not found a way to use ADL to get the address of bar.
So my question is, how can I take the address of bar? Is there any other way than to define bar outside of foo?
You could declare the friend function in the enclosing namespace scope in a different translation unit:
In foo.hpp:
#include <iostream>
struct foo;
void (*get_bar_address())(foo);
struct foo {
friend void bar(foo) {}
void foobar() {
std::cout << get_bar_address() << '\n'; // no error
}
};
In foo.cpp
#include "foo.hpp"
void bar(foo);
void (*get_bar_address())(foo){
return bar;
}
It seems to be impossible to get exactly what you want. The problem is that an inline friend declared function will only be found by argument-dependant lookup, as defined in the C++ standard 11 and 14 in
7.3.1.2
3 Every name first declared in a namespace is a member of that namespace. If a friend declaration in a non-local class first declares a class or function the friend class or function is a member of the innermost enclosing namespace. The name of the friend is not found by unqualified lookup (3.4.1) or by qualified lookup (3.4.3) until a matching declaration is provided in that namespace scope (either before or after the class definition granting friendship). If a friend function is called, its name may be found by the name lookup that considers functions from namespaces and classes associated with the types of the function arguments (3.4.2). If the name in a friend declaration is neither qualified nor a template-id and the declaration is a function or an elaborated-type-specifier, the lookup to determine whether the entity has been previously declared shall not consider any scopes outside the innermost enclosing namespace.
That means it is only ever be found by argument dependent lookup. Revising the rules, argument dependent lookup is only applied within a function call expression. Hence you will not be able to retrieve the address of the function as any such an expression will evaluate to the result of the call.
In case you only need a pointer referring to a function with the same functionality as bar, you could however utilize lambdas to get a pointer to such a function nevertheless.
void foo::foobar() {
using fntype = void(*)(foo);
std::cout << (fntype)[](foo f){ bar(f); } << '\n'; // error
}
The downside is that any other lambda will likely result in an intirely different address. You could however offer the address in a different (static) member function if the uniqueness is of importance.
Did you try something like this? I find it interesting that you would declare a friend function from inside the scope of the struct/class but hey.
#include <iostream>
// forward declare foo so you can forward declare bar :)
struct foo;
// forward declare bar so an address is available on the line that references it.
void bar(foo);
struct foo
{
friend void bar(foo)
{
std::cout << "bar called" << std::endl;
}
void foobar()
{
std::cout << "address of bar " << &bar << '\n'; // error
}
};
int main()
{
bar(foo{}); // ok, visible through ADL
foo{}.foobar();
}
Tried it and it works LOL not sure why:
$ ./test.exe
bar called
address of bar 1
though address of 1 is suspicious. :) but hey it compiled and did something. maybe you can take it further or someone can explain why this compiled/worked in the first place.
I have the following code:
struct M {
friend void f() {}
M() {
f(); // error: 'f' was not declared in this scope
}
};
int main() {
M m;
}
Live example
Both g++4.8 and clang3.4 fail to compile it, because f is not visible inside M, or so they say.
However, the Standard gives an example of a similar code
class M {
friend void f() { } // definition of global f, a friend of M,
// not the definition of a member function
};
and says that
A friend function defined in a class is in the (lexical) scope of the
class in which it is defined.
(ISO/IEC 14882:2011 11.3 Friends [class.friend] p6, p7)
From this I can't understand how compiler can't find f which is defined in same class where it's used.
It's kinda unlikely that both compilers have the same bug.
So, what did I miss?
The friend declaration states that a function called f in the surrounding namespace is a friend of the class; but it does not introduce the name f into the namespace. It's not available (except by argument-dependent lookup) until it's been declared in the namespace.
The relevant rule is C++11 7.3.1.2/3:
If a friend declaration in a non-local class first declares a class or function the friend class or function is a member of the innermost enclosing namespace. The name of the friend is not found by unqualified lookup or by qualified lookup until a matching declaration is provided in that namespace scope.
This quote from the C++ Standard
A friend function defined in a class is in the (lexical) scope of the
class in which it is defined.
means the following
9 Name lookup for a name used in the definition of a friend function
(11.3) defined inline in the class granting friendship shall proceed
as described for lookup in member function definitions.
That is any name used in the function is searched starting from the class scope.
However the function itself is not visible in the namespace until it will be declared outside the class.
So in your case it is enough to declare the function before the class definition
void f() {}
struct M {
friend void f();
M() {
f();
}
};
int main() {
M m;
}
Or
void f();
struct M {
friend void f() {}
M() {
f();
}
};
int main() {
M m;
}
The critical question is under what circumstances is the compiler able/allowed to find your function declaration.
For a general friend function, you have to declare it outside of the class such that the compiler is able to find it.
However there is a very useful exception: If the the friend function has an argument of class type, it is able to find the function without additional declaration due to argument-dependent name lookup.
This case is actually very important because normally you would want a friend function to access an object of class type.
Consider the following example:
#include <iostream>
struct M
{
friend void printI(int a) {
std::cout << a;
}
friend void print(const M& m) { // friend takes object of class type!
std::cout << "M";
}
void foo() {
printI(2); // ERROR - requires declaration!
print(*this); // OK!
}
};
int main()
{
M m;
m.foo();
printI(2); // ERROR - requires declaration!
print(m); // OK
}
struct M {
friend void f() {}
M() {
f(); // error: 'f' was not declared in this scope
}
};
int main() {
M m;
}
The above code works perfectly.(tried on DevC++)
Also try not to define the function inside the class as it might not have a scope outside it i.e. in main().
In trying to call f() from main() you'll receive an error saying function doesn't exist.
Therefore, define function outside classes using :: operator (if necessary) so that there is no problem accessing the function from anywhere.
Access friend function defined in class
Compiling the following:
void bar() { /* ... */ }
void foo()
{
struct MyStruct
{
friend void bar();
};
}
int main()
{
//..
}
results in the error:
error: friend declaration 'void bar()' in local class without prior declaration
Why does name lookup fail? How can I fix it?
You can't access a local class out of its enclosing scope even if you friend things becuase The name of a local class is local to its enclosing scope - §9.8/1.
However if you just want to get it to compile, explicitly tell it it look in global scope...
friend void ::bar();
*This fixes it in VS but not in GCC for some reason
§11.3/11 (thanks jrok)
If a friend declaration appears in a local class (9.8) and the name specified is an unqualified name, a prior
declaration is looked up without considering scopes that are outside the innermost enclosing non-class scope.
After searching aroung SO, one question taught me that the lexical scope of an inline friend function is the class it's defined in, meaning it can access e.g. the typedefs in the class without qualifying them. But then I wondered what is the actual scope of such a function? GCC at least rejects all my attempts to call it. Can a function such as in the example ever be called through means other than ADL, which is not possible here thanks to no arguments?
Standard quotations are appreciated, as I currently can't access my copy of it.
The following code
namespace foo{
struct bar{
friend void baz(){}
void call_friend();
};
}
int main(){
foo::baz(); // can't access through enclosing scope of the class
foo::bar::baz(); // can't access through class scope
}
namespace foo{
void bar::call_friend(){
baz(); // can't access through member function
}
}
results in these errors:
prog.cpp: In function ‘int main()’:
prog.cpp:9: error: ‘baz’ is not a member of ‘foo’
prog.cpp:10: error: ‘baz’ is not a member of ‘foo::bar’
prog.cpp: In member function ‘void foo::bar::call_friend()’:
prog.cpp:15: error: ‘baz’ was not declared in this scope
When you declare a friend function with an unqualified id in a class it names a function in the nearest enclosing namespace scope.
If that function hasn't previously been declared then the friend declaration doesn't make that function visible in that scope for normal lookup. It does make the declared function visible to argument-dependent lookup.
This is emphasised in many notes, but the definitive statement is in 7.3.1.2/3 (of ISO/IEC 14882:2011):
Every name first declared in a namespace is a member of that namespace. If a friend declaration in a non-local class first declares a class or function the friend class or function is a member of the innermost enclosing namespace. The name of the friend is not found by unqualified lookup (3.4.1) or by qualified lookup (3.4.3) until a matching declaration is provided in that namespace scope (either before or after the class definition granting friendship). If a friend function is called, its name may be found by the name lookup that considers functions from namespaces and classes associated with the types of the function arguments (3.4.2). If the name in a friend declaration is neither qualified nor a template-id and the declaration is a function or an elaborated-type-specifier, the lookup to determine whether the entity has been previously declared shall not consider any scopes outside the innermost enclosing namespace.
"The C++ Programming Language 3rd Edition (Stroustrap)" : p279:
I. "Like a member declaration, a friend declaration does not introduce a name into an enclosing scope"
II. "A friend class must be previously declared in an enclosing scope or defined in the nonclass
scope immediately enclosing the class that is declaring it a friend"
III. "A friend function can be explicitly declared just like friend classes, or it can be found through its argument types (§8.2.6) as if it was declared in the nonclass
scope immediately enclosing its class."
IV. "It follows that a friend function should either be explicitly declared in an enclosing scope or take an argument of its class. If not, the friend cannot be called. For example:"
//no f() here
void g();
class X{
friend void f(); //useless
friend void g(); //can be found because it is declared outside of class scope
friend void h(const X&); //can be found because the arguments access class members
};
void f() { } //enemy of X :)
But in your case there is more to it that has to do with the namespace, because if you put the proper declaration in foo e.g.:
namespace foo{
struct bar{
friend void baz(const &bar){};
void call_friend();
}
}
does not compile. However, if you declare it outside foo is works like a charm. Now consider that in fact, global, local, struct, and classes are in fact namespaces. Now this leads to the conclusion that the baz(const &) is implicitly defined in the global scope.
This compiles:
namespace foo{
struct bar{
friend void baz(const bar&){};
void call_friend();
};
}
int main(){
foo::bar k;
baz(k);
return 0;
}
Therefore, there are two issues:
The friend declaration does not introduce a name in an enclosing scope, unless IV. Thus the original program cannot find baz() because it has not been properly declared.
If IV , i.e. ADL, then the function is found in foo, but cannot be accessed as foo::baz(k), due to ADL. You will have to explicitely define baz(const bar&) in foo to access it by qualified name.
Thanks, hope it helps, but certainly, I liked the challenge :) .
Interesting!
It seems that the compiler does not know what scope it belongs to (and to be honest there are no clues) and thus puts in in no scope. Some standard digging coming up I suppose.
Note: If you explicitly add a declaration to a particular scope then it starts to work as expected.
namespace foo
{
void baz(); // declare it here and now it works in foo namespace etc.
struct bar
{
friend void baz(){}
void call_friend();
};
}
Digging the standard I find:
11.3 Friends [class.friend]
Paragraph 6
A function can be defined in a friend declaration of a class if and only if the class is a non-local class (9.8), the function name is unqualified, and the function has namespace scope.
[ Example:
class M { friend void f() { } // definition of global f, a friend of M,
// not the definition of a member function
};
— end example ]
Paragraph 7
Such a function is implicitly inline. A friend function defined in a class is in the (lexical) scope of the class in which it is defined. A friend function defined outside the class is not (3.4.1).
Note:
A free standing function that does not take a parameter is not much use as a friend. As it will have no object on which to take advantage of its friendship (I suppose file scope static storage duration objects).
A friend function defined within an enclosing class, will only be found by argument dependent lookup (ADL). Calling it will succeed when one or more of the arguments is either of the enclosing class type; or of a type declared within the class. Here is an example, displaying "Hello World!", which (for variety) doesn't use an object of the enclosing class type to provide such an argument:
#include <iostream>
struct foo
{
struct local_class{};
friend void greet(local_class o, int) { std::cout << "Hello World!\n"; }
};
int main(int argc, char *argv[])
{
foo::local_class o;
greet(o,1);
return 0;
}
In this Example,
namespace foo{
struct bar{
friend void baz(){}
void call_friend();
};
}
int main(){
foo::baz(); // can't access through enclosing scope of the class
foo::bar::baz(); // can't access through class scope
}
namespace foo{
void bar::call_friend(){
baz(); // can't access through member function
}
}
foo::baz() is inaccessible because the name baz is not visible in scope of namespace foo. If I remember correctly (§ 3.4/2) applies here.
foo::bar::baz() is inaccessible because friends aren't members of class and the scope of inline friend function is namespace or class in which their definition exists therefore, you can't access them outside of that scope.
If you put the declaration of baz() in foo the name of function baz will be visible in foo and the definition will be looked up in the nested scope of bar.
namespace foo{
void baz(); // declaration at namespace scope
struct bar{
friend void baz(){}
};
void call_friend() {
baz(); // ok
}
}
int main()
{
foo::baz(); // ok, bar will be looked up in the nested scope of foo::bar.
}
I think you are confusing friend and private. By declaring function a friend you are granting it access to your private members, and not grating other functions access to it. Anyway, any member function of a struct is accessible by any object because struct members are public by default.
However, in your case baz isn't accessible because by doing friend void baz(){} you didn't really declare the function baz, you just said that it is a friend function. You can just remove the friend keyword, and it will solve all the issues.