template <typename T, size_t N>
char (&ArraySizeHelper(T (&array)[N]))[N];
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
我见过其他模板可以做同样的事情,比如 使用模板获取数组的大小和结束地址。
我理解这些,但我一直在这方面遇到困难。
函数模板名为
ArraySizeHelper
,该函数接受一个参数、对 T [N]
的引用,并返回对 char [N]
的引用。
宏将您的对象(假设它是
X obj[M]
)作为参数传递。编译器推断出 T == X
和 N == M
。所以它声明了一个返回类型为 char (&)[M]
的函数。然后宏用 sizeof
包装这个返回值,所以它实际上是在做 sizeof(char [M])
,即 M
。
如果给它一个非数组类型(例如
T *
),那么模板参数推断将会失败。
正如@Alf 在下面指出的那样,这种混合模板宏系统相对于替代的仅模板方法的优势在于,它为您提供了一个编译时常量。
这不是最好的方法,但既然你问:模板函数
ArraySizeHelper
的返回类型是char[N]
,其中函数的参数是一个(引用)大小的数组N 类型为T
。模板参数推导使用匹配的数字 N 实例化该模板,因此 sizeof(char[N])
就是 N,这就是您得到的。
更好的版本可以写如下。 (
constexpr
需要 C++11;如果省略它,这将不是常量表达式。)
template <typename T, size_t N> constexpr size_t array_size(const T (&)[N]) { return N; }
用途:
int x[20];
array_size(x); // == 20
更新: 如果您使用 C++11,这里是另一个提供 constexpr 的解决方案,感谢 decltype:
#include <type_traits>
template <typename T> struct array_traits;
template <typename T, unsigned int N> struct array_traits<T[N]>
{
static const unsigned int size = N;
typedef std::decay<T>::type type;
};
// Usage:
int x[20];
array_traits<decltype(x)>::size; // == 20
std::size
来获取数组的大小。
MSDN 上的这篇博客准确地描述了它的工作原理。非常有趣的故事。看看吧。