Templated Member Function Pointers
How can we use member function pointers with templated member functions?
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.
Member Function Pointers and Binding
Explore advanced techniques for working with class member functions