Pointers to Members

Lambda Member Function Pointers

Is it possible to create a member function pointer to a lambda that's stored as a class member?

Abstract art representing computer programming

While you can't create a direct member function pointer to a lambda, there are several ways to achieve similar functionality. There are three possible approaches below.

Using std::function

Here, we use the std::function wrapper:

#include <functional>
#include <iostream>

class Character {
public:
  Character() {
    // Initialize lambda member
    Attack = [this](int Damage){
      Health -= Damage;
      std::cout << "Took " << Damage <<
        " damage. Health: " << Health << '\n';
    };
  }

  void TakeDamage(int Amount) {
    Attack(Amount);
  }

private:
  int Health{100};
  std::function<void(int)> Attack;
};

int main() {
  Character player;
  player.TakeDamage(30);
  player.TakeDamage(20);
}
Took 30 damage. Health: 70
Took 20 damage. Health: 50

Using Template Member

We can set this up using a template member as follows:

#include <functional>
#include <iostream>

class Character {
public:
  template <typename F>
  void SetAttackBehavior(F&& Lambda) {
    Attack = std::forward<F>(Lambda);
  }

  template <typename... Args>
  void ExecuteAttack(Args&&... args) {
    Attack(std::forward<Args>(args)...);
  }

private:
  std::function<void(int)> Attack = [](int){
    std::cout << "No attack behavior set\n";
  };
};

int main() {
  Character player;

  // Default behavior
  player.ExecuteAttack(10);

  // Set new behavior
  player.SetAttackBehavior(
    [](int Damage){
      std::cout << "Dealing " << Damage <<
        " damage!\n";
    });

  player.ExecuteAttack(20);
}
No attack behavior set
Dealing 20 damage!

Using Variant Pattern

Here’s another example where we provide a SetAttackMethod() allowing external code to switch behaviors:

#include <functional>
#include <iostream>

class Character {
public:
  enum class AttackType { Melee, Ranged };

  void SetAttackType(AttackType Type) {
    switch (Type) {
    case AttackType::Melee:
      CurrentAttack = [this](int Damage){
        std::cout << "Melee attack: " << Damage
          << '\n';
      };
      break;
    case AttackType::Ranged:
      CurrentAttack = [this](int Damage){
        std::cout << "Ranged attack: " << Damage
          << '\n';
      };
      break;
    }
  }

  void Attack(int Damage) {
    CurrentAttack(Damage);
  }

private:
  std::function<void(int)> CurrentAttack
    = [](int){
      std::cout << "No attack set\n";
    };
};

int main() {
  Character player;

  player.Attack(10);

  player.SetAttackType(
    Character::AttackType::Melee);
  player.Attack(20);

  player.SetAttackType(
    Character::AttackType::Ranged);
  player.Attack(30);
}
No attack set
Melee attack: 20
Ranged attack: 30

Key considerations:

  • std::function has more overhead than raw member function pointers
  • Lambdas capturing this must ensure object lifetime
  • Template approach can be more efficient but less flexible
  • Consider using type erasure for complex scenarios
  • Be careful with circular references in captures
  • Lambda storage may increase object size

The choice between these approaches depends on your specific needs:

  • Use std::function for maximum flexibility
  • Use templates for better performance
  • Use variant pattern for structured behavior switching
  • Consider combining approaches for complex systems

Answers to questions are automatically generated and may not have been reviewed.

A computer programmer
Part of the course:

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Free, unlimited access

This course includes:

  • 125 Lessons
  • 550+ Code Samples
  • 96% Positive Reviews
  • Regularly Updated
  • Help and FAQ
Free, Unlimited Access

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Screenshot from Warhammer: Total War
Screenshot from Tomb Raider
Screenshot from Jedi: Fallen Order
Contact|Privacy Policy|Terms of Use
Copyright © 2024 - All Rights Reserved