通过引用c++中的模板函数来传递数组
Passing an array by reference to template function in c++
下面的代码对我来说很好。
#include <iostream>
using namespace std;
template<class T>
T sum_array(T (&a)[10], int size)
{
T result=0;
for(int i=0; i<size; i++)
{
result = a[i] + result;
}
return result;
}
int main()
{
int a[10] = {0,1,2,3,4,5,6,7,8,9};
cout<<sum_array(a, 10)<<endl;
double d[10] = {1.1,1.1,1.1,1.1,1.1,1.1,1.1,1.1,1.1,1.1};
cout<<sum_array(d, 10)<<endl;
cin.get();
}
但是,如果试图通过删除函数中如下所示的数组大小来使我的函数更通用,则会出现一个错误,表示没有函数模板的实例。
template<class T>
T sum_array(T (&a)[], int size)
{
T result=0;
for(int i=0; i<size; i++)
{
result = a[i] + result;
}
return result;
}
同时,如果我删除如下所示的引用,它会很好地工作。
template<class T>
T sum_array(T a[], int size)
{
T result=0;
for(int i=0; i<size; i++)
{
result = a[i] + result;
}
return result;
}
我对模板比较陌生,你能解释一下上面的行为吗。
在函数参数中,[]
(内部没有维度)只是指针的替代语法,因为数组在传递到函数中时会衰减为指针,除非它们是通过引用传递的。
这意味着您的工作通用模板(具有T a[]
的模板)与T a*
完全相同。如果您在运行时传递大小,那么一切都很好,您可以直接使用它(它将适用于其他未声明为数组的东西,例如std::string::c_str()
的返回值)。
然而,如果你想推广tempalte,但仍然将其限制在实际阵列中,你可以这样做:
template<class T, size_t N>
T sum_array(T (&a)[N], int size)
{
T result=0;
for(int i=0; i<size; i++)
{
result = a[i] + result;
}
return result;
}
这样,只有一个真正的数组可以传入,但它的类型T
和长度N
都将被推导出来。根据您的用例,在这种情况下,您可能会删除size
参数。
如果您想通过引用绑定数组,您绝对需要知道数组的大小。不过,可以让编译器推断大小。假设代码中的逻辑是非平凡的,那么最好立即委托给与数组大小无关的版本。这里有一个例子:
template<typename T>
T sum_array(T const* a, int size)
{
return std::accumulate(a, a + size, T());
}
template <typename T, int Size>
T sum_array(T const (&array)[Size]) {
return sum_array(array, Size);
}
当然,我忍不住也使用<numeric>
中的std::accumulate()
:如果有算法的话,使用它是个好主意
由于您想知道是否要从数组中删除引用:当对函数参数的类型使用T[]
时,它相当于使用T*
。即使使用T[10]
作为函数参数的类型,编译器也会将其读取为T*
。
为了提供关于其他所说内容的参考,请参阅模板参数推导:
在扣除开始之前,对p和A的以下调整是制造:
- 如果P不是参考类型
a) 如果a是数组类型,则a为替换为从数组到指针获得的指针类型转变
b) 否则,如果A是函数类型,则将A替换为从函数到指针的转换获得的指针类型;
c) 否则,如果A是cv限定类型,则顶级cv限定符被忽略以进行扣除:
template<class T> void f(T);
int a[3];
f(a); // P = T, A = int[3], adjusted to int*: deduced T = int*
void b(int);
f(b); // P = T, A = void(int), adjusted to void(*)(int): deduced T = void(*)(int)
const int c = 13;
f(c); // P = T, A = const int, adjusted to int: deduced T = int
如果p是cv合格类型,忽略顶级cv限定符进行推导。
如果p是引用类型,引用类型用于推导。
如果p是对cv不合格模板参数的右值引用(所谓转发引用),相应的函数调用参数为对于推导(注:这是std::forward作用的基础注意:在类模板参数推导中类模板从来都不是转发引用(因为C++17)):
基本上,1-a)意味着试图通过值传递数组会触发数组到指针的转换(衰减),从而丢失静态大小信息,而3则表示通过引用传递是保持原始的完整类型及其大小。1-a)
顺便说一句,在非模板上下文中似乎也会发生同样的情况(可能需要有人提供引用:数组到指针的转换)。
这是一个可能的例子:
#include <iostream>
template <size_t N>
constexpr size_t Size(const char [N]) {
return N;
}
template <size_t N>
constexpr size_t Size2(const char (&)[N]) {
return N;
}
void Test(const char [5]) {
std::cout << "Passing array by value" << std::endl;
}
template<typename T>
void Test2(const T [3]) {
std::cout << "Template passing array by value" << std::endl;
}
void Testr(const char (&)[5]) {
std::cout << "Passing array by reference" << std::endl;
}
template<typename T>
void Testr2(const T (&)[3]) {
std::cout << "Template passing array by reference" << std::endl;
}
int main() {
// pointer to array decay, N cannot be deduced
// std::cout << Size("Test") << std::endl;
// reference to "sized" array, N can be deduced
std::cout << Size2("Test") << std::endl;
// also pointer to array decay, even in non template context, size provided in signature is not used
Test("Test");
Test("TestTest");
// pointer to array decay, size provided in signature is not used
Test2("Test");
Test2("TestTest");
Testr("Test");
// reference to "sized" array, size provided in signature is checked
// Testr("TestTest");
// Testr2("Test");
return 0;
}
实时演示
- 第 i 个元素返回 i 的函数数组
- 使用嵌套函数数组是个好主意吗?
- 正确实现类函数数组
- 试图引用已删除函数数组的相等运算符
- 如何在静态函数中使用成员函数数组
- 无法创建函数数组
- 构造函数数组
- 使用开关或定义函数数组 - 更快
- 编写一个函数,该函数将覆盖主函数数组中的值
- 可以像'funs[1]();'一样调用的函数数组
- std::AVX内部函数数组
- 如果数组大小未知,如何将函数数组作为参数传递
- 从函数数组中获取值
- 使用元编程在编译时初始化函数数组
- 将C函数数组转换为C++函数指针数组
- 复制构造函数 [数组] C++
- 添加函数数组并随机选择其中一个
- 指针到私有成员函数数组
- 可以单独声明函数数组的元素
- (c++)将main中的随机值保存到函数数组中