Friend declaration and the entity it denotes - c++

I have one question about friend functions/classes. Consider the following code:
#include <iostream>
struct A
{
private:
int a = 5;
friend int foo(A a);
};
int foo(A a)
{
return a.a;
}
int a = foo(A());
int main(){ std::cout << a << std::endl; }
DEMO
It works fine and both int foo() within class scope and global scope refer to the same entity. Although, the declaration of int foo() within the class scope didn't introduce a name into the global scope. If it were then we would recieve a linker-error intstead of compile-error in the code:
#include <iostream>
struct A
{
private:
int a = 5;
friend int foo();
};
int a = foo(); //undeclared foo
int main(){ std::cout << a << std::endl; }
DEMO
I can't find explanation about this in the Standard. What it says is N3797:11.3/6 [class.friend]:
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.
So, it explains why the following code works fine:
#include <iostream>
struct A
{
private:
int a = 5;
friend int foo(A a)
{
return a.a;
}
};
int a = foo(A());
int main(){ std::cout << a << std::endl; }
DEMO
We defined the function in the friend declaration and, as the Standard said it became the member of the global namespace. But the rule covers the defintion, not declaration. Obviously, that's not any declaration is definition. So we can't apply one to the first example.

In the last program
#include <iostream>
struct A
{
private:
int a = 5;
friend int foo(A a)
{
return a.a;
}
};
int a = foo(A());
int main(){ std::cout << a << std::endl; }
The compiler finds definition of function foo only due to the argument dependent lookup.
You should consider the following section of the C++ Standard
3.4.2 Argument-dependent name lookup
2 For each argument type T in the function call, there is a set of
zero or more associated namespaces and a set of zero or more
associated classes to be considered. The sets of namespaces and
classes is determined entirely by the types of the function
arguments (and the namespace of any template template argument).
Typedef names and using-declarations used to specify the types do not
contribute to this set.
Thus in this program the compiler searches the function in the scope of the class because the argument of the function has the class type. If you will change the function definition for example the following way then the compiler will not find the function.
#include <iostream>
struct A
{
public:
A( int x ) : a( 2 * x ) {}
private:
int a;
friend int foo( int x )
{
A a( x );
return a.a;
}
};
int a = foo( 10 );
int main()
{
std::cout << a << std::endl;
return 0;
}
But if you add a declaration of the function in the scope where the class is defined then the compiler will see the function
#include <iostream>
struct A
{
public:
A( int x ) : a( 2 * x ) {}
private:
int a;
friend int foo( int x )
{
A a( x );
return a.a;
}
};
int foo( int );
int a = foo( 10 );
int main()
{
std::cout << a << std::endl;
return 0;
}
Here the program output is
20

Related

How to initialize a reference member variable inside a member function & access it inside other member functions - C++

The usual method one'd use for normal variables (declaring outside the member functions & initializing inside a member function) doesn't work, as reference variables need to be initialized & declared in same line.
#include <iostream>
using namespace std;
class abc {
public:
int& var;
void fun1 (int& temp) {var=temp;}
void fun2 () {cout << abc::var << endl;}
abc() {}
};
int main() {
abc f;
int y=9;
f.fun1(y);
f.fun2();
return 0;
}
How to initialize a reference member variable inside a member function & access it inside other member functions - C++
Use a pointer.
#include <iostream>
using namespace std;
class abc {
public:
int* var;
void fun1 (int& temp) { var = &temp; }
void fun2 () { cout << *abc::var << endl; }
abc() {}
};
int main() {
abc f;
int y=9;
f.fun1(y);
f.fun2();
return 0;
}
I think this is the best you can do.
#include <iostream>
using namespace std;
class abc {
public:
int& var;
abc(int& temp) :
var(temp)
{}
void fun2 () {cout << abc::var << endl;}
};
int main() {
int y=9;
abc f(y);
f.fun2();
return 0;
}
A reference is a constant thing — it refers to the same integer for the entire lifespan of the object. That means you need to set it on construction.
int var; int& varref = abc::var;
This should work!

Use an external function as a method of a class

I'm trying to make this code work:
#include <iostream>
using namespace std;
int f(int x) {
return x+1;
}
class A {
public:
int g(int y);
};
int A::g(int y) = f;
int main() {
A test;
cout << test.g(3) << endl;
return 0;
}
It does not compile because of the line int A::g(int y) = f;.
What is the correct way to achieve that an external function can be used as a method?
You can use a pointer to function as a member of class A. Now assign function f to g member of A.
int f(int x) {
return x+1;
}
class A {
public:
int (*g)(int);
};
int main(){
A test;
test.g = f;
cout << test.g(10); // prints 11
}
You can accomplish the same by making your function a callable objects by implementing () operator. so you can have that as member of the class, and then it can normally be used as function on the class objects.
#include <iostream>
struct do_something{
int operator()(int num){
return num;
}
};
class test{
int sum;
public:
do_something fun;
};
int main(){
test obj;
std::cout << obj.fun(10);
}

std::function incomplete type on const function

Consider the following code which works as expected:
#include <iostream>
#include <functional>
struct foo
{
std::function<int()> get;
};
struct bar
{
int get()
{
return 42;
}
};
int main()
{
foo f;
bar b;
f.get = std::bind(&bar::get, &b);
if (f.get())
std::cout << "f.get(): " << f.get() << std::endl;
return 0;
}
Now, let's assume that bar::get() is a const member function:
#include <iostream>
#include <functional>
struct foo
{
std::function<int()const> get;
};
struct bar
{
int get() const
{
return 42;
}
};
int main()
{
foo f;
bar b;
f.get = std::bind(&bar::get, &b);
if (f.get())
std::cout << "f.get(): " << f.get() << std::endl;
}
Using GCC 9.2, this snipped throws the following compiler error:
main.cpp:6:31: error: field 'get' has incomplete type 'std::function<int() const>'
6 | std::function<int()const> get;
| ^~~
In file included from /usr/local/include/c++/9.2.0/functional:59,
from main.cpp:2:
/usr/local/include/c++/9.2.0/bits/std_function.h:128:11: note: declaration of 'class std::function<int() const>'
128 | class function;
| ^~~~~~~~
I fail to understand why foo::get has incomplete type.
Could somebody point me towards the right direction for understanding this behavior and "fixing" it accordingly?
I have the need to bind a const member function to a function pointer.
int()const is an abominable type.
std::function<int()const> is not a type, because it doesn't match the only defined specialisation
namespace std {
template< class R, class... Args >
class function<R(Args...)> { ... };
}
Just use std::function<int()>.
The const bit only makes sense for member functions. You've already bound bar::get to an instance b to save it as a std::function.
As mentioned by #KamilCuk:
The constness is checked at std::bind, not at std::function
You don't need to pass explicit const to std::function. Just use your older prototype: std::function<int()>. It will work if you don't have const overload (that mean, you have either one of these int bar::get() or int bar::get() const) for the same member function (Otherwise, you need to type cast explicity).
Actually, your function (int bar::get() const) will be having a signature like this (behind the scenes):
// int bar::get() const
int get(const bar *const this)
{
return 42;
}
// int bar::get()
int get(bar *const this)
{
return 42;
}
If you have overloads and want to bind specific member function, you can do something like this:
typedef int(bar::*fptr)(void) const; // or remove const
std::bind((fptr)&bar::get, &b );
See this:
#include <iostream>
#include <functional>
#include <vector>
struct foo
{
std::function<int()> get;
};
struct bar
{
int get()
{
return 42;
}
int get() const
{
return 50;
}
};
int main()
{
foo f;
bar b;
typedef int (bar::*fptr)(void);
typedef int (bar::*fcptr)(void) const;
f.get = std::bind((fptr)&bar::get, &b);
if (f.get())
std::cout << "f.get(): " << f.get() << std::endl;
f.get = std::bind((fcptr)&bar::get, &b);
if (f.get())
std::cout << "f.get(): " << f.get() << std::endl;
}
Output:
f.get(): 42
f.get(): 50
std::bind does not pass through constness to the callable. Therefore, the following would work:
struct foo {
std::function<int()> get;
// ^ note there is no 'const'
};

Question about C++ call virtual function implemented in base from derived class

What is wrong with the following code?
struct A {
virtual int hash() const = 0;
virtual int hash(int x) const = 0;
};
struct B : public A {
int hash() const final {
return 10;
};
int hash(int x) const override {
return 10;
};
};
struct C : public B {
int hash(int x) const override {
return x;
}
};
#include <iostream>
int main() {
C a;
std::cout << a.hash() << std::endl;
std::cout << a.hash(20) << std::endl;
return 0;
}
I got compile error with the following error message
xx.cc:26:23: error: too few arguments to function call, single argument 'x' was
not specified
std::cout << a.hash() << std::endl;
~~~~~~ ^
xx.cc:17:3: note: 'hash' declared here
int hash(int x) const override {
^
1 error generated.
This is name hiding issue. According to the rule of name lookup,
(emphasis mine)
name lookup examines the scopes as described below, until it finds at least one declaration of any kind, at which time the lookup stops and no further scopes are examined.
So C::hash hides the name from the base class.
You can apply using to introduce the name into the class C scope.
struct C : public B {
using B::hash;
int hash(int x) const override {
return x;
}
};
Yeah, you have to redefine the overload within the derived class.
struct C : public B {
int hash(int x) const override {
return x;
}
int hash() const override {
return B::hash();
}
};
Or alternatively call via a reference to B
int main() {
C a;
B& b = a;
std::cout << b.hash() << std::endl;
std::cout << b.hash(20) << std::endl;
return 0;
}

Is it possible to pass a struct's member variable as parameter

I am trying to associate a struct's member variable with a class. So that when I create a new class, I can specify that it is associated with this member variable in a struct. For example:
struct A {
int a;
int b;
};
static A a[2];
a[0].a = 1;
a[0].b = 2;
a[1].a = 3;
a[1].b = 4;
class foo {
public:
foo(int index, ???) {
c = a[index].???; //Is it possible to define the 2nd parameter as a getter of struct A's member? So this line could resolve to either a[index].a or a[index].b?
}
private:
int c;
};
So that:
new foo(0, ???) would set c to 1 given ??? refer to A::a
new foo(0, ???) would set c to 2 given ??? refer to A::b
new foo(1, ???) would set c to 3 given ??? refer to A::a
new foo(1, ???) would set c to 4 given ??? refer to A::b
Yes, it is possible, you need to pass a data member pointer:
#include <iostream>
struct A
{
int a;
int b;
};
static A a[2]
{
1, 2
, 3, 4
};
class foo
{
public: int c;
public:
foo(int const index, int A::* const p_field)
{
c = a[index].*p_field;
}
};
int main()
{
foo const f1(0, &A::a);
::std::cout << f1.c << ::std::endl;
foo const f2(0, &A::b);
::std::cout << f2.c << ::std::endl;
foo const f3(1, &A::a);
::std::cout << f3.c << ::std::endl;
foo const f4(1, &A::b);
::std::cout << f4.c << ::std::endl;
return 0;
}
Check this code at online compiler
You have a couple options. If you just want the integer (like you have in your code you've posted), then just take an integer as a parameter to the constructor and pass it the right number.
class foo {
public:
foo(int val) {
c = val
}
private:
int c;
};
int main() {
foo f(a[0].b);
}
Or you could take a reference to an integer. This way if one changes, the other will as well:
class foo {
public:
foo(int &val) : c(val) { } //need to use an initialization list for this one
private:
int &c;
};
int main() {
foo f(a[0].b);
a[0].b = -1; //f.c will be -1 now as well
}
Using a data member pointer as in VTT's answer is the most direct solution but I often find member pointers and member function pointer syntax a bit cumbersome and I believe it is hard for the compiler to optimize.
For these kind of things I prefer to use a stateless lambda. You can pass a lambda to a function template and then the compiler can easily optimize it away:
#include <iostream>
struct A {
int a;
int b;
};
static A a[2]{{1, 2}, {3, 4}};
class foo {
public:
int c;
public:
template<typename F>
foo(int index, F getter) { c = getter(a[index]); }
};
int main() {
auto agetter = [](const A& a){ return a.a; };
auto bgetter = [](const A& a){ return a.b; };
foo const f1(0, agetter);
std::cout << f1.c << "\n";
foo const f2(0, bgetter);
std::cout << f2.c << "\n";
foo const f3(1, agetter);
std::cout << f3.c << "\n";
foo const f4(1, bgetter);
std::cout << f4.c << "\n";
}