template<typename T, size_t n>
size_t array_size(const T (&)[n])
{
return n;
}
我没有得到的部分是这个模板函数的参数。当我将数组传递给数组时,数组会发生什么情况n
?
好吧,首先你必须明白,试图从数组中获取一个值可以给你一个指向它的第一个元素的指针:
int a[] = {1, 2, 3};
int *ap = a; // a pointer, size is lost
int (&ar)[3] = a; // a reference to the array, size is not lost
引用使用它们的确切类型或它们的基类类型来引用对象。关键是模板通过引用获取数组。C++ 中不存在作为参数的数组(不是对它们的引用)。如果你给一个参数一个数组类型,它将是一个指针。所以当我们想知道传递数组的大小时,使用引用是必要的。大小和元素类型是自动推导出来的,通常是函数模板的情况。以下模板
template<typename T, size_t n>
size_t array_size(const T (&)[n]) {
return n;
}
使用我们之前定义的数组调用a
将隐式实例化以下函数:
size_t array_size(const int (&)[3]) {
return 3;
}
可以这样使用:
size_t size_of_a = array_size(a);
我前段时间做了一个变体[编辑:原来有人在这里已经有了同样的想法],它可以在编译时确定一个值。它不是直接返回值,而是根据以下条件为模板提供返回类型n
:
template<typename T, size_t n>
char (& array_size(const T (&)[n]) )[n];
您说如果数组有n
元素,则返回类型是对具有 sizen
和 element type的数组的引用char
。现在,您可以获得传递数组的编译时确定的大小:
size_t size_of_a = sizeof(array_size(a));
char
因为具有元素的数组具有n
sizeof n
,所以它也会为您提供给定数组中元素的数量。在编译时,所以你可以做
int havingSameSize[sizeof(array_size(a))];
因为该函数实际上从未被调用过,所以不需要定义它,所以它没有主体。希望我能把这件事弄清楚一点。
这样想,假设你有一堆函数:
// Note that you don't need to name the array, since you don't
// actually reference the parameter at all.
size_t array_size(const int (&)[1])
{
return 1;
}
size_t array_size(const int (&)[2])
{
return 2;
}
size_t array_size(const int (&)[3])
{
return 3;
}
// etc...
现在,当您调用它时,会调用哪个函数?
int a[2];
array_size(a);
现在,如果您将数组大小模板化,您将得到:
template <int n>
size_t array_size(const int (&)[n])
{
return n;
}
编译器将尝试实例化与您调用它的任何参数相匹配的 array_size 版本。所以如果你用一个 10 个整数的数组来调用它,它会用 n=10 实例化 array_size。
接下来,只需将类型模板化,这样您就可以使用不仅仅是 int 数组来调用它:
template <typename T, int n>
size_t array_size(const T (&)[n])
{
return n;
}
你完成了。
编辑:关于(&)
需要括号&
来区分 int 引用数组(非法)和对 int 数组的引用(你想要的)。由于 的优先级[]
高于&
,如果您有声明:
const int &a[1];
由于运算符优先级,您最终会得到一个对 int 的 const 引用的单元素数组。如果你想&
先应用,你需要用括号强制它:
const int (&a)[1];
现在,您有一个对 int 的单元素数组的 const 引用。在函数参数列表中,不使用参数的名称不需要指定,所以可以去掉名称,但保留括号:
size_t array_size(const int (&)[1])
数组没有任何反应。它是一个未使用的参数,用于解析模板函数的签名。
它也不能用作模板参数,但这是一个单独的 nit。
对于我们这些没有“constexpr”的人来说,一种将结果作为编译时 const 的奇怪方法:
#include <iostream>
namespace
{
template <size_t V>
struct helper
{
enum
{
value = V
};
};
template<typename T, size_t Size>
auto get_size(T(&)[Size]) -> helper < Size >
{
return helper < Size >() ;
}
template<typename T>
struct get_value
{
enum
{
value = T::value
};
};
}
int main()
{
std::cout << get_value<decltype(get_size("Foo bar baz"))>::value;
}