我一直在用c++做一些练习,偶然发现了一个,它是关于创建一个简单的模板化函数迭代器,它接受任何类型的数组和另一个模板化函数在数组中的每个元素中做一些处理,我已经完成了下面的练习:
template <typename T >
void increment(T& t) {
t += 1;
}
template <typename T, typename F>
void iterate(T *arr, size_t size, F f) {
for (size_t i = 0; i < size; i++) f(arr[i]);
}
int main( void ) {
int tab[]= {0,1,2,3,4};
SomeClass tab2[5];
iterate(tab, 5, increment<int>);
iterate(tab2, 5, increment<SomeClass>);
return (0);
}
主函数中的那两个测试是我自己写的,现在练习也提供了一些测试来检查解决方案,它的测试几乎是一样的,它使用一个简单的print()
模板函数而不是increment()
template <typename T >
void print(const T& t) {std::cout << t << " "; };
现在这里的问题是它使用以下模板函数实例化iterate()
:
iterate(tab, 5, print);
iterate(tab2, 5, print);
现在根据我的理解你不能传递一个模板化的函数作为参数没有实例化,因为它不是一个常规的函数,它应该被实例化,否则编译器将不知道什么类型创建实际的函数??事实上,当我编译练习的测试时,我得到了一个:
no matching function for call to 'iterate'
所以我的问题是我是正确的,这只是练习中的一个错误,还是测试是正确的,我是那个错过了一些东西的人?
是的,你是正确的。函数模板不能作为模板实参传递,因为它还没有类型。
可以传递的是一个函子,可以是重载operator()
的自定义函子,也可以只是一个lambda。你确定这里没有提到函子吗?
下面的代码可以工作:
auto print = [](const auto& t) {std::cout << t << " "; };
iterate(tab, 5, print);
iterate(tab2, 5, print);
这也是许多STL算法采用的方法。
任务可能期望您使用函数指针。在某些场景下,可以推导出print
的参数类型。注意,如果你想要修改函数和非修改函数(=接受const引用的函数)都工作,你需要为模板指定模板参数,该模板的签名可以匹配这两个,例如你的increment
模板。
template <typename T >
void increment(T& t)
{
t += 1;
}
template <typename T>
void iterate(T* arr, size_t size, void (*f)(const T&)) {
for (size_t i = 0; i < size; i++) f(arr[i]);
}
template <typename T>
void iterate(T* arr, size_t size, void(*f)(T&)) {
for (size_t i = 0; i < size; i++) f(arr[i]);
}
template <typename T >
void print(const T& t) { std::cout << t << " "; };
int main(void) {
int tab[] = { 0,1,2,3,4 };
iterate(tab, 5, increment<int>); // not possible to deduce the template parameter for increment here (both const int and int would be signatures matching an overload of iterate)
iterate(tab, 5, print); // template parameter of print deduced as int
}