📖
Go C++
  • Introduction
  • Chapter 1: What You Must Know First
    • Virtual Address Space of Process: Memory Partition and Layout
    • Function Call: Stack Frame
    • Program Compiling and Linking
  • Chapter 2: C++ Basics Improvement
    • Default Parameters
    • Inline Function
    • Function Overloading
    • new and delete
    • const and Pointers
    • References in Detail
  • Chapter 3: Object-Oriented Principles
  • Class and Object
  • Constructor and Destructor
  • Shallow Copy and Deep Copy
  • Initializer List
  • Various Member Functions
  • Pointer to Class Members
  • Chapter 4: Template Programming
  • Function Templates
  • Class Templates
  • Memory Allocators
  • Chapter 5: Operator Overloading
    • Operator Overloading
    • Introduction to Iterators
    • Issues of Iterator Invalidation
    • More about new and delete
    • Overloading of new and delete: Object Pool
  • Chapter 6: Inheritance and Polymorphism
    • Look inside Inheritance
    • More about Inheritance
    • Virtual Functions, Static Binding and Dynamic Binding
    • More about Virtual Functions
    • Understanding Polymorphism
    • Abstract Classes
    • Frequently Asked Interview Questions: Polymorphism
  • Chapter 7: Multiple Inheritance
    • Virtual Inheritance and Virtual Base Classes
    • Diamond Problem
    • Four Kinds of Type Conversions
  • Chapter 8: Standard Template Library
    • Sequence Containers
    • Container Adaptors
    • Associative Containers
    • More about Iterators
    • Function Objects
    • Generic Algorithms, Binders and Lambda Expressions
  • Chapter 9: Object Optimization
    • Behind the Object
    • Optimizing Objects in Functions
    • Member Functions with Rvalue References
    • Move Semantics and Perfect Forwarding
  • Chapter 10: Smart Pointers
    • Smart Pointers
    • Smart Pointers without Reference Counting
    • Smart Pointers with Reference Counting
    • Custom Deleters
  • Chapter 11: Function Objects and Binders
    • More about Binders
    • Introduction to std::function
    • Template Specialization and Argument Deduction
    • More about std::function
    • std::bind(): A Simple Thread Pool
    • More about Lambda Expressions
  • Chapter 12: Multithreading
    • Important Features in C++11
    • Multithreaded Programming with std::thread
    • Mutual Exclusion
    • Producer-Consumer Problem
    • Atomic Operations
    • Thread Visibility and volatile
  • Chapter 13: Design Patterns
    • Singleton Pattern
    • Factory Pattern
    • Proxy Pattern
    • Decorator Pattern
    • Adapter Pattern
    • Observer Pattern
Powered by GitBook
On this page

Was this helpful?

  1. Chapter 11: Function Objects and Binders

More about Lambda Expressions

Function objects are powerful, but every time we use a function object we need to define a class for it, which has a poor flexibility. In many cases we don't want to explicitly define a class, then we can use lambda expressions instead.

In previous chapters we have already used lambda expressions a lot. Lambda expression is also known as an anonymous function since it can serve as a function without being given a name. A lambda function has the following syntax:

[External variables](Parameters)->Retuen value {Function Content}

The following example is a lambda expression which prints "Hello World" to the console. We use a function object to store it and call the function with operator =.

int main() {
    auto f1 = []()->void {cout << "Hello World!" << endl;};
    f1();   // Hello World!
    return 0;
}

With lambda expression, the compiler will automatically generate a function object class for as, something like this:

template <typename T = void>
class Lambda1 {
public:
    Lambda1() {}
    void operator() const {
        cout << "Hello World!" << endl;
    }
};

Another example use lambda expression to calculate the sum of two integers:

int main() {
    auto f2 = [](int a, int b)->void {return a};
    cout << f2(10,20) << endl;  // 30
    return 0;
}

This expression is equivalent to using a function object looks like:

template <typename T = void>
class Lambda2 {
public:
    Lambda2() {}
    int operator(int a, int b) const {
        return a + b;
    }
};

Inside the square brackets [] is the external variables we want to lambda expression to capture. Its usage is as follows:

  • []: No external variable is captured.

  • [=]: All external variables are captured and passed by value.

  • [&]: All external variables are captured and passed by reference.

  • [this]: *this pointer of an object is captured.

  • [=, &a]: All external variables are captured and passed by value, but a is passed by reference.

  • [a, b]: a and b are captured and passed by value.

Now if we have lambda expression which takes two value and swap their values. Obviously, we should pass these two values by reference here:

int main() {
    int a = 10;
    int b = 20;
    auto f3 = [&a, &b]()->void {
        int tmp = a;
        a = b;
        b = tmp;       
    };
    f3();
    cout << a << endl;  // 20
    cout << b << endl;  // 10
    return 0;
}

It is equal to have a function object with two member variables which are initialized by reference, and operator () swap these two variables.

template <typename T = void>
class Lambda3 {
public:
    Lambda3(int &a, int &b) : ma(a), mb(b) {}
    int operator(int a, int b) const {
        int tmp = ma;
        ma = mb;
        mb = tmp;    
    }
private:
    int &ma;
    int &mb;
};

Since lambda expression is actually a function object, we can use std::function to store it as well. The following example is a map whose key is an integer and value is a std::function object with two int parameters and return type int. Then we can use this map to store lambda expressions of arithmetic operations.

int main() {
    map<int, function<int(int, int)>> m;
    map[1] = [](int a, int b)->int{ return a + b;};
    map[2] = [](int a, int b)->int{ return a - b;};
    map[3] = [](int a, int b)->int{ return a * b;};
    map[4] = [](int a, int b)->int{ return a / b;};
    cout << m[1](10, 20) << endl;   // 30
    cout << m[2](10, 20) << endl;   // -10
    return 0;
}
Previousstd::bind(): A Simple Thread PoolNextImportant Features in C++11

Last updated 4 years ago

Was this helpful?