C++: STL Adapters

In lesson 38 we learned about function objects.

Now, we'll learn about function adapters — transforming existing functions into the form you need.

Like LEGO bricks, using small pieces to build something bigger.


1. Adapter Overview

(1) 1.1 What Are Adapters?

Adapters are templates that modify the behavior of function objects.

Common adapters:



2. std::bind — Argument Binding

(1) 2.1 Basic Usage

std::bind is used to bind function arguments, creating new function objects.

Example: Binding arguments (Difficulty ⭐⭐)

▶ Example 2: Code Example (Difficulty ⭐)

CPP
#include <iostream>
#include <functional>

int add(int a, int b) {
 return a + b;
}

int main() {
 // Bind the first argument of add to 10
 auto add10 = std::bind(add, 10, std::placeholders::_1);
 
 std::cout << "add10(5) = " << add10(5) << std::endl; // Output: 15
 std::cout << "add10(20) = " << add10(20) << std::endl; // Output: 30
 
 return 0;
}
▶ Try it Yourself

Output:

TEXT 📖 Display only
add10(5) = 15
add10(20) = 30

💡 Tip:


(2) 2.2 Reordering Arguments

Example: Swapping argument order (Difficulty ⭐⭐)

CPP
#include <iostream>
#include <functional>

int subtract(int a, int b) {
 return a - b;
}

int main() {
 // Swap argument order
 auto reverse_subtract = std::bind(subtract,
 std::placeholders::_2,
 std::placeholders::_1);
 
 std::cout << "subtract(10, 3) = " << subtract(10, 3) << std::endl; // 7
 std::cout << "reverse(10, 3) = " << reverse_subtract(10, 3) << std::endl; // -7
 
 return 0;
}


3. std::ref — Reference Wrapping

(1) 3.1 The Problem: Pass by Value

By default, STL algorithms pass function objects by value, which means state cannot be shared.

Example: Solving with std::ref (Difficulty ⭐⭐)

CPP
#include <iostream>
#include <algorithm>
#include <vector>
#include <functional>

struct Counter {
 int count = 0;
 void operator()(int) { count++; }
};

int main() {
 std::vector<int> v = {1, 2, 3, 4, 5};
 Counter counter;
 
 // ❌ Wrong! Pass by value, a copy of counter is called
 std::for_each(v.begin(), v.end(), counter);
 std::cout << "Count: " << counter.count << std::endl; // Output: 0
 
 // ✅ Correct! Use std::ref to pass by reference
 std::for_each(v.begin(), v.end(), std::ref(counter));
 std::cout << "Count: " << counter.count << std::endl; // Output: 5
 
 return 0;
}


4. std::not_fn — Negation

(1) 4.1 Basic Usage

std::not_fn is used to negate the return value of a function object.

Example: Negating a predicate (Difficulty ⭐⭐)

CPP
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>

int main() {
 std::vector<int> v = {1, 2, 3, 4, 5};
 
 // Find the first even number
 auto it1 = std::find_if(v.begin(), v.end(),
 (int x) { return x % 2 == 0; });
 std::cout << "First even: " << *it1 << std::endl; // 2
 
 // Find the first odd number (negation)
 auto it2 = std::find_if(v.begin(), v.end(),
 std::not_fn((int x) { return x % 2 == 0; }));
 std::cout << "First odd: " << *it2 << std::endl; // 1
 
 return 0;
}


5. std::mem_fn — Member Function Pointer

(1) 5.1 The Problem: Member Function Pointers Are Hard to Use

Member function pointer syntax is complex; std::mem_fn simplifies it.

Example: Calling member functions (Difficulty ⭐⭐⭐)

TEXT 📖 Display only
#include <iostream>
#include <vector>
#include <algorithm>
#include <memory>

struct Student {
 std::string name;
 void display() const {
 std::cout << "Student: " << name << std::endl;
 }
};

int main() {
 std::vectorStudent students = {{"Zhang San"}, {"Li Si"}};
 
 // Use std::mem_fn to call member function
 std::for_each(students.begin(), students.end(),
 std::mem_fn(&Student::display));
 
 return 0;
}


6. Comprehensive Example

▶ Example 1: Flexible Score Processor (Difficulty ⭐⭐⭐)

CPP
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>

int main() {
 std::vector<int> scores = {85, 92, 78, 90, 88};
 int threshold = 90;
 
 // Count how many scores are not lower than threshold
 int count = std::count_if(scores.begin(), scores.end(),
 std::bind(std::greater_equalint(),
 std::placeholders::_1,
 threshold));
 
 std::cout << "Number of scores >= " << threshold << ": " << count << std::endl;
 
 return 0;
}
▶ Try it Yourself

Output:

TEXT 📖 Display only
Number of scores >= : 

❓ FAQ

Q: Is std::bind still relevant in C++11? A: Yes, but Lambda is more recommended. Lambda is more concise and performs better.

TEXT 📖 Display only
// Using std::bind
auto f1 = std::bind(add, 10, std::placeholders::_1);

// Using Lambda (recommended)
auto f2 = (int x) { return add(10, x); };

Q Can stack and queue use other containers as their underlying implementation?
A Yes! Adapters specify the underlying container through template parameters: stack<int, vector<int>> uses vector; queue<int, list<int>> uses list. By default, stack uses deque, and queue also uses deque.

▶ Example 3: Queue (Difficulty ⭐)

CPP
#include <iostream>
#include <queue>

int main() {
    std::queue<int> q;

    q.push(10);
    q.push(20);
    q.push(30);

    while (!q.empty()) {
        std::cout << "Front: " << q.front() << std::endl;
        q.pop();
    }

    return 0;
}
▶ Try it Yourself

Output:

TEXT 📖 Display only
Front: 
💡 Tip: A queue is a First-In-First-Out (FIFO) structure. Use push() to enqueue, front() to access the front element, and pop() to dequeue.


📖 Summary


📝 Exercises

  1. Basic (Difficulty ⭐): Create a stackint, push 1, 2, 3 in order, then loop and pop all elements. Observe the output order.

  2. Intermediate (Difficulty ⭐⭐): Use queue to implement a "print job queue" — simulate multiple print jobs being processed in order, outputting the remaining queue length after each job is processed.

  3. Challenge (Difficulty ⭐⭐⭐): Use priority_queue to implement a "task scheduler" — each task has a priority (1-10), the queue processes tasks from highest to lowest priority, with ties broken by insertion order.



Next lesson: Exception Handling (#40)

Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏