Lambda, member function, free function in C++

I want to know the difference between Lambda and Named function in C++.

Let's first learn few terms 'free function', 'forward declaration', and 'named function'.

Free Function 

 In C++ simply refers to non-member functions. Every function that is not a member function is a free function.
struct X {
    void f() {}               // not a free function
};
void g() {}                   // free function
int h(int, int) { return 1; } // also a free function


Invoking a member function from a member function


// friend functions
#include <iostream>
using namespace std;

class Rectangle {
protected:
int width, height;
int find_area(int x, int y) const
{
return x*y;
}
};

class Square : public Rectangle
{
public:
int duplicate (const int& l, const int& r)
{
int res = find_area(l, r); //int res = this->find_area(l, r);
return res;
}
};

int main () {
Square sq;
cout << sq.duplicate (2, 3) << endl;

return 0;
}


Click here to work on the above program. 

The implicit *this will invoke a member function as Square inherited Rectangle. The below both 
are same. 

int res = find_area(l, r); 
int res = this->find_area(l, r);

If duplicate is not a member function, there will not be an implicit *this. 

Invoking a member function from a freestanding(non-member)


To call a member function from freestanding function, befriending the free function won't be suffice. 

// friend functions
#include <iostream>
using namespace std;

class Rectangle {
protected:
int width, height;
int find_area(int x, int y) const
{
return x*y;
}
public:
friend int duplicate (const int&, const int&);
};

int duplicate (const int& l, const int& r)
{
int res = find_area(l, r);
return res;
}

int main () {
cout << duplicate (2, 3) << endl;

return 0;
}



Output

<source>: In function 'int duplicate(const int&, const int&)':
<source>:18:13: error: 'find_area' was not declared in this scope
18 | int res = find_area(l, r);
| ^~~~~~~~~
Click here for the above program 

The above program requires an instance of the class.

There are two ways to achieve this:

1. Pass a reference to duplicate

2. 

Pass a class reference to a free function


// friend functions
#include <iostream>
using namespace std;

class Rectangle {
int width, height;
int find_area(int x, int y) const
{
return x*y;
}
public:
Rectangle() {}
friend int duplicate (const int&,
const int&,
const Rectangle&);
};

int duplicate (const int& l, const int& r,
const Rectangle& param)
{
int res = param.find_area(l, r);
return res;
}

int main () {
Rectangle rec;
cout << duplicate (2, 3, rec) << endl;

return 0;
}

Output

6

Click here for the above program.





Forward Declaration 

Forward declaration refers to the beforehand declaration of the syntax or signature of an identifier, variable, function, class, etc. prior to its usage (done later in the program)

If a class B is defined after class A, but class A's member function uses the class B, it might throw error if Class A's object is first initialised. 

Named Function

Named function is a function which has name unlike Lambda. 

Eg: member function & free functions. 

What is Lambda?

  • Lambdas are user-defined nameless functions, but it is not a user-define function. 
  • Lambda is not a function. It is neither a free function nor a named function. 
  • A lambda is an object of a closure type with an overloaded call operator.
  • Lambda can't have forward declaration. 

Practically you define something akin to

[captures]( parameters ){ body; }

class __lambda_SOME_ID
{
    captures ...;
    auto operator( parameters ... )
    {
       body;
    }
};

The major difference is that they "capture" some variables from the scope that they're defined within.

Lambda has no declaration

Since Lambda doesn't have names, they can't be declared. Because, you can't name its type beforehand. 

They just get defined. Lambda is defined and used it to initialize a reference to that function. The reference is called print.


Lambdas don't have scope as they don't have names. Scope applies to name visibility and not lifetime. 

Lambdas are mostly used for small things that you only need locally within another function. I.e. as a predicate to a standard algorithm.

We don't want to care about the functionality of the below code because we are interested only to know the difference between lambda and name function. 

#include <iostream>
#include <vector>
using namespace std;

vector<int> convert(int x) {
  vector<int> ret;
  do {
      ret.push_back(x & 1);
  }while(x>>=1);
  reverse(ret.begin(),ret.end());
  return ret;
}

auto print = [] (auto const& v) {
   for(const auto& e : v) { cout << e << " "; }
   cout << endl;
};

int printStd(vector<int> v) {
    for (auto i = v.begin(); i != v.end(); i++) {
        cout << *i << " ";    
    } 
    return 0;
}

int main() 
{
    int x = 98;
    vector<int> y = convert(x);
    print(y);    // Method 1 - Lambda
    printStd(y); // Method 2 - user defined function
    
     return 0;       
}

Output:

1
2
1 1 0 0 0 1 0
1 1 0 0 0 1 0
1 1 0 0 0 1 0


Print lambda can print any iterable whereas named function printStd does accept only vector of integers. print is the identifier of a Lambda. Lambda uses auto template feature so it does accept any data type. Let's make both function accept any data type. So, let's change it first.

#include <iostream>
#include <vector>
using namespace std;

vector<int> convert(int x) {
  vector<int> ret;
  do {
      ret.push_back(x & 1);
  }while(x>>=1);
  reverse(ret.begin(),ret.end());
  return ret;
}

auto print = [] (auto const& v) {
   for(const auto& e : v) { cout << e << " "; }
   cout << endl;

};

template <typename T>
int printStd(auto v) {
    for (auto i = v.begin(); i != v.end(); i++) {
        cout << *i << " ";    
    } 
    cout << endl;
    return 0;
}

int main() 
{
    int x = 98;
    vector<int> y = convert(x);
    print(y);    // Method 1 - Lambda
    printStd(y); // Method 2 - user defined function

    return 0;       
}


Warning

main.cpp:20:14: warning: use of ‘auto’ in parameter declaration only available with ‘-fconcepts’

   20 | int printStd(auto v) {

Output:

1
2
Line 14: error: ISO C++ forbids declaration of 'print' with no type
compilation terminated due to -Wfatal-errors.


auto is not used for regular function, so you can use template.

Click here to debug the code. 

#include <iostream>
#include <vector>

using namespace std;

vector<int> convert(int x) {
  vector<int> ret;
  do {
      ret.push_back(x & 1);
  }while(x>>=1);
  reverse(ret.begin(),ret.end());
  return ret;
}

auto print = [] (auto const& v) {
   for(const auto& e : v) { cout << e << " "; }
   cout << endl;
};

template <typename T>
int printStd(T& v) {
    for (auto i = v.begin(); i != v.end(); i++) {
        cout << *i << " ";    
    } 
    cout << endl;
    return 0;
}

int main() 
{
    int x = 98;
    vector<int> y = convert(x);
    print(y);    // Method 1 - Lambda
    printStd(y); // Method 2 - user defined function

    return 0;       
}


Output:
1 1 0 0 0 1 0 
1 1 0 0 0 1 0 


References 

SO link1 - free function

gfg link - forward declaration

reddit link

cppstories.com

Comments