有人可以解释这个模板代码,给我一个数组的大小?
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; }
调用我们以前定义的数组将会隐式地实例化下面的函数:
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
元素,返回类型是一个大小为n
,元素类型为char
的数组的引用。 现在,你可以得到一个编译时确定的传递数组的大小:
size_t size_of_a = sizeof(array_size(a));
因为具有n
元素的char
数组的大小为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 int (&a)[1];
现在你有一个int的一个元素数组的const引用。 在函数参数列表中,如果不使用它,则不需要指定参数的名称,因此可以删除名称,但保留小括号:
size_t array_size(const int (&)[1])
阵列没有任何反应。 这是一个未使用的参数,用于解析模板函数的签名。
它也不能被用作模板参数,但这是一个单独的尼特。
对于没有“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; }