As an exercise I am trying to write an array implementation using templates, but with a function pointer as a template parameter. This function would be called every time the array gets indexed.
template<typename T, int size>
using Array_fnIndex = void (*)(int index);
template<typename T, int size, typename Array_fnIndex<T, size> fnIndex>
struct Array {
T data[size];
T& operator[](int index) {
fnIndex(index);
return data[index];
}
};
// example index function
template<typename T, int size>
void checkIndex(int index) {
assert(index < size);
}
int main() {
Array<int, 10, checkIndex<int, 10>> a; // this works
Array<int, 10, checkIndex<int, 11>> b; // this also works, not what I want
Array<int, 10, checkIndex> c; // this doesn't work, but what I want
return 0;
}
The last Array declaration in the main
function is what I would like, where the template parameters of checkIndex match the previous template parameters in Array. However this doesn't compile (using Microsoft compiler). I get the following error:
error C2440: 'specialization': cannot convert from 'void (__cdecl *)(uint)' to 'void (__cdecl *)(uint)'
note: None of the functions with this name in scope match the target type
Is there any way to get the desired result where the template parameters for the provided function get inferred from the other parameters?
May not be applicable in your real use case, but I suggest a callable object containing a function that does the check:
template<typename T, int size, typename fnIndex>
struct Array {
T data[size];
T& operator[](int index) {
fnIndex{}.template check<size>(index);
return data[index];
}
};
struct checkIndex {
template<int size>
void check(int index) {
assert(index < size);
}
};
int main() {
Array<int, 10, checkIndex> c;
return 0;
}
wandbox example
Let's analyze fnIndex{}.template check<size>(index)
:
fnIndex{} // make a temporary object of type `fnIndex`
.template check<size>(index) // call its `check` method using `size`
// as a template argument and `index` as
// as a function argument
The .template
disambiguation syntax is required because the compiler does not know what check
means - it could be a field and the line could be interpreted as:
fnIndex{}.check < size > (index)
where <
is the less-than operator, >
is the greater-than operator, and (index)
is an expression.
Using .template
tells the compiler that we want to invoke a template method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With