Lambda Member Function Pointers
Is it possible to create a member function pointer to a lambda that's stored as a class member?
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
Pointers to Members
Learn how to create pointers to class functions and data members, and how to use them