Member Function Pointers and Binding

Templated Member Function Pointers

How can we use member function pointers with templated member functions?

Abstract art representing computer programming

Using member function pointers with templated member functions in C++ requires some additional considerations and techniques. Here's how you can work with them effectively.

Basic Syntax

To create a pointer to a templated member function, you need to specify the template parameters:

#include <iostream>

class MyClass {
 public:
  template <typename T>
  void print(T value) {
    std::cout << "Value: " << value;
  }
};

int main() {
  void (MyClass::*ptr)(int) =
    &MyClass::print<int>;

  MyClass obj;
  (obj.*ptr)(42);
}
Value: 42

Using std::mem_fn()

std::mem_fn() can be used with templated member functions, but you need to specify the template parameters:

auto printInt = std::mem_fn(&MyClass::print<int>);
MyClass obj;
printInt(obj, 42);// Outputs: Value: 42

Function Templates for Generic Usage

To work with different template instantiations, you can create function templates:

#include <iostream>

class MyClass {
 public:
  template <typename T>
  void print(T value) {
    std::cout << "Value: " << value << '\n';
  }
};

template <typename T>
void callPrint(MyClass& obj, T value) {
  void (MyClass::*ptr)(T) = &MyClass::print<T>;
  (obj.*ptr)(value);
}

int main() {
  MyClass obj;
  callPrint(obj, 42);
  callPrint(obj, 3.14);
  callPrint(obj, "Hello");
}
Value: 42
Value: 3.14
Value: Hello

Storing in Data Structures

When storing pointers to templated member functions in data structures, you typically need to decide on the specific template instantiation:

#include <functional>
#include <vector>
#include <iostream>

class Printer {
public:
  template <typename T>
  void print(T value) {
    std::cout << "Printing: " << value << '\n';
  }
};

int main() {
  std::vector<std::function<void
    (Printer&, int)>> intPrinters;
  intPrinters.push_back(&Printer::print<int>);

  Printer p;
  for (const auto& printer : intPrinters) {
    printer(p, 42);
  }
}
Printing: 42

Variadic Templates

For member functions with variadic templates, you can use perfect forwarding:

#include <iostream>
#include <utility>

class Logger {
public:
  template <typename... Args>
  void log(Args&&... args) {
    (std::cout << ... << args) << '\n';
  }
};

template <typename... Args>
void callLog(Logger& logger, Args&&... args) {
  // Declare a pointer to the log method
  void (Logger::*ptr)(Args&&...) = &Logger::log<
    Args&&...>;
  // Invoke the method using the pointer
  (logger.*ptr)(std::forward<Args>(args)...);
}

int main() {
  Logger logger;
  callLog(logger, "Hello, ", 42, ", ", 3.14);
}
Hello, 42, 3.14

Limitations and Considerations

  • Template argument deduction doesn't work with member function pointers, so you always need to explicitly specify the template arguments.
  • You can't have a single member function pointer that works with all template instantiations. Each instantiation is a different function.
  • When using with std::function or similar type-erasing wrappers, you need to specify the concrete types.

Alternative: Type Erasure

For more flexibility, you can use type erasure techniques:

#include <memory>
#include <vector>
#include <iostream>

class PrinterBase {
public:
  virtual void print() const = 0;
  virtual ~PrinterBase() = default;
};

template <typename T>
class PrinterImpl : public PrinterBase {
public:
  PrinterImpl(T value) : value_(value) {}

  void print() const override {
    std::cout << "Value: " << value_ << '\n';
  }

private:
  T value_;
};

class MyClass {
public:
  template <typename T>
  void addPrinter(T value) {
    printers_.push_back(
      std::make_unique<PrinterImpl<T>>(value));
  }

  void printAll() const {
    for (const auto& printer : printers_) {
      printer->print();
    }
  }

private:
  std::vector<std::unique_ptr<PrinterBase>>
  printers_;
};

int main() {
  MyClass obj;
  obj.addPrinter(42);
  obj.addPrinter(3.14);
  obj.addPrinter("Hello");
  obj.printAll();
}
Value: 42
Value: 3.14
Value: Hello

This approach allows you to work with different template instantiations without needing to store function pointers directly.

Using member function pointers with templated member functions can be powerful, but it requires careful consideration of template instantiation and type handling.

These techniques allow you to create flexible, generic code that can work with a wide variety of types while still leveraging the benefits of member function pointers.

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

sdl2-promo.jpg
Part of the course:

Game Dev with SDL2

Learn C++ and SDL development by creating hands on, practical projects inspired by classic retro games

Free, unlimited access

This course includes:

  • 55 Lessons
  • 100+ Code Samples
  • 91% 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