Function Pointers and Templates
How do function pointers interact with function templates?
Function pointers and function templates can interact in interesting and powerful ways, but they also present some challenges. Let's explore this relationship in detail.
Basic Function Templates
First, let's remind ourselves what a function template looks like:
#include <iostream>
template<typename T>
T Add(T a, T b) {
return a + b;
}
int main() {
std::cout << Add(5, 3) << "\n";
std::cout << Add(5.5, 3.2);
}
8
8.7
The compiler generates specific functions based on the types used when calling the template function.
Function Pointers to Template Functions
When using function pointers with template functions, we need to be explicit about which instantiation of the template we're referring to:
#include <iostream>
template <typename T>
T Multiply(T a, T b) { return a * b; }
int main() {
int (*intMultiply)(int, int) = Multiply<int>;
double (*doubleMultiply)(double, double) =
Multiply<double>;
std::cout << intMultiply(5, 3) << "\n";
std::cout << doubleMultiply(5.5, 3.2);
return 0;
}
15
17.6
Here, we're creating function pointers to specific instantiations of the Multiply
template function.
Challenges with Template Deduction
One challenge is that template argument deduction doesn't work with function pointers. This won't compile:
template<typename T>
T Square(T x) {
return x * x;
}
int main() {
auto funcPtr = Square;
}
error: unable to deduce 'auto' from 'Square'
The compiler can't deduce which instantiation of Square
to use because there's no context for type deduction.
Solutions to Template Deduction
We can solve this in a few ways. We can specify the template arguments explicitly:
#include <iostream>
template<typename T>
T Square(T x) {
return x * x;
}
int main() {
auto funcPtr = Square<int>;
std::cout << funcPtr(5);
}
25
Alternatively, use a type alias with a specific type:
#include <iostream>
template<typename T>
T Square(T x) {
return x * x;
}
using IntSquare = int(*)(int);
int main() {
IntSquare funcPtr = Square;
std::cout << funcPtr(5);
}
25
Function Templates with Non-Type Parameters
Function templates can also have non-type parameters, which can be used with function pointers:
#include <array>
#include <iostream>
template <typename T, size_t Size>
void PrintArray(
const std::array<T, Size>& arr) {
for (const auto& item : arr) {
std::cout << item << " ";
}
std::cout << "\n";
}
int main() {
std::array<int, 3> intArr = {1, 2, 3};
std::array<double, 2> doubleArr = {1.1, 2.2};
void (*intPrinter)(const std::array<int, 3>&)
= PrintArray;
void (*doublePrinter)(
const std::array<double, 2>&) = PrintArray;
intPrinter(intArr);
doublePrinter(doubleArr);
}
1 2 3
1.1 2.2
In this case, both the type and the non-type template parameters are part of the function pointer type.
Understanding these interactions is crucial when working with both function templates and function pointers in C++. While they provide a lot of flexibility, they also require careful handling to ensure type safety and avoid compilation errors.
Callbacks and Function Pointers
Learn to create flexible and modular code with function pointers