📖
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 std::function

std::function can be used to bind a function into a function object. Then corresponding functions can be called through function objects.

void foo(string str) {
    cout << str << endl;
}
​
int main() {
    function<void(string)> f = foo;
    foo("foo()");   // foo()
    return 0;
}

Now let's implement our own myfunction class for foo(). Since foo() takes one parameter and a return value, we have two parameters for the template as well. First we need to have a basic template class, and then write the specialized one. The class stores a function pointer of type R(*)(A1), and operator() simply calls the function with the pointer, and returns its return value.

template <typename R, typename A1>
class myfunction {};
​
template <typename R, typename A1>
class myfunction<R(A1)> {
public:
    using PFUNC = R(*)(A1);
    myfunction(PFUNC pfunc) : _pfunc(pfunc) {}
    R operator()(A1 a1) {
        return _pfunc(a1);
    }
private:
    PFUNC _pfunc;
};
​
int main() {
    myfunction<void(string)> f = foo;
    f("foo()"); // foo()
    return 0;
}

Similarly, if we have a function sum() which takes two arguments, we need to write another specialized template class as well. This time the template has three parameters.

template <typename R, typename A1, typename A2>
class myfunction<R(A1, A2)> {
public:
    using PFUNC = R(*)(A1, A2);
    myfunction(PFUNC pfunc) : _pfunc(pfunc) {}
    R operator()(A1 a1, A2 a2) {
        return _pfunc(a1, a1);
    }
private:
    PFUNC _pfunc;
};
​
int sum(int a, int b) {
    return a + b;
}
​
int main() {
    myfunction<void(string)> f = sum;
    cout << f(10, 20) << endl;  // 30
    return 0;
}

There is a problem here: functions with different number of parameters should have different version of myfunction. Should we write all of them? It seems impossible. Fortunately, templates are so powerful in C++ that they support variable number of parameters with operator .... We need to add ... wherever the parameters are uncertain:

template <typename R, typename... A>
class myfunction<R(A...)> {
public:
    using PFUNC = R(*)(A...);
    myfunction(PFUNC pfunc) : _pfunc(pfunc) {}
    R operator()(A... a) {
        return _pfunc(a...);
    }
private:
    PFUNC _pfunc;
};

Now the compiler will automatically generate the correct version of myfunction when instantiating objects.

PreviousTemplate Specialization and Argument DeductionNextstd::bind(): A Simple Thread Pool

Last updated 5 years ago

Was this helpful?