2010-05-31 51 views
2

寻找一种方法可以做到便携,安全,元素计数C风格的数组,我发现这个解决方案:是便携式的函数引用sizeof?

template <typename T, unsigned N> char (&arrayCountofHelper(T(&)[N]))[N]; 
#define ARRAY_COUNTOF(arr) (sizeof(arrayCountofHelper(arr))) 

好像arrayCountofHelper实际上是一个函数的引用,和宏ARRAY_COUNTOF用途一个函数的大小是它的返回类型的大小这一事实。
它工作得很好。
但是,当我试图检查它是否可移植时,我没有找到任何证据。我无法在标准(14882/1998)中找到对sizeof(函数引用)的任何引用,事实上,我不完全确定我可以甚至创建一个函数引用(尽管标准提到了几个次)。
那么,有人知道我应该看什么标准吗? (或者,如果我误解了声明一些如何,什么是正确的解释?)

感谢
奥伦

附: (对于那些你们谁认为我没有找到我的问题的合适的解决方案)
我知道我可以随时使用

#define ARRAY_COUNTOF sizeof(arr)/sizeof(arr[0]) 

甚至

template <typename T, unsigned N> size_t arrayCountof(T(&)[N]) {return N;} 

,但首先会不会检查arr是一个数组(或指针),第二个在static_assert内不可用。
(我会使用的std :: TR1 ::阵列或std ::矢量,但是这是一个旧的代码我维持)

+2

查看此答案的其他解释:http://stackoverflow.com/questions/437150/can-someone-explain-this-template-code-that-gives-me-the-size-of-an-array/437178#437178(底部) – 2010-05-31 20:27:58

回答

4

我们将宽松地选择这个,我使用INCITS + ISO + IEC + 14882-2003。我会引用小东西,但一些更复杂的东西太大而不能引用。

sizeof在第5.3.3节所定义,并且它说(删节):

sizeof运算产生在其操作数的对象表示的字节数。操作数可以是一个表达式,它不会被评估,或者是一个带括号的类型标识符。

换句话说,它以字节为单位产生一个类型的大小,或者找到一个表达式的类型并产生一个表达式的大小。我们没有类型,我们有表达式arrayCountofHelper(arr)

您可以通过查看分别在§5.1和§5.2中定义的primary-expressionpostfix-expression的定义来剖析此表达式。你会发现它是一个postfix-expression并符合函数调用的要求(第5.2.2节)。

现在回到sizeof。我们只关心这个函数调用表达式的类型(所以我们可以产生它的大小)和§5.2。2/3说:

函数调用表达式的类型是静态选择函数[...]的返回类型。该类型应为完整的对象类型,引用类型或类型void

所以我们需要找到将被调用的函数的返回类型(请记住,这是所有未评估)与arrayCountofHelper(arr)arrayCountofHelper是一个函数模板,我们将实例化(第14.7节),所以我们需要这样做,然后才能获得返回类型的实例化函数。

所有模板参数都需要有值(第14.8.2节),并且通过使用第14.8.2.1节中定义的规则,我们将通过将传递给该函数的数组与匹配函数参数(其中是对数组的引用)。 (例如,如果arrint[10],T将是int并且N将是10.)一旦我们有了这些,函数就可以被实例化。

一旦实例化,函数的返回类型将是char(&)[N] *,该参数是对数组Nchar的数组。 (如果需要帮助解析,请参阅第8.3.5节。关于如何解析“复杂”类型,还有关于SO的问题。)现在我们已经找到了表达式的类型,我们必须考虑它的大小。

第5.3.3节/ 2定义如何sizeof作品与参考文献和阵列(重点煤矿):

当施加到一个参考或引用类型,其结果是被引用类型的大小。当应用于类时,结果是该类的对象中的字节数,包括将该类型的对象放入数组所需的任何填充。大多数派生类的大小应大于零(1.8)。将sizeof应用于基类子对象的结果是基类类型的大小。70)应用于数组时,结果是数组中的字节总数。这意味着n个元素数组的大小是元素大小的n倍。

引用类型的大小是其引用类型的大小,所以我们需要的char[N]大小。这个尺寸是N * sizeof(char)char是最基本的,因为它是最小的类型;也就是sizeof(char)总是其中之一。 (§5.3.3/ 1)所以这个表达式产生的大小是1 * N,或者我们想要的全部时间:N

这就是它的工作原理。


这一个优于的arrayCountof你的最后一个例子的原因是因为的sizeof结果是常量表达式,这样可以在需要的常量表达式地方使用。

应当指出的是,C++ 0x中,我们可以得到我们的清洁无宏观语法有:

template <typename T, unsigned N> 
constexpr size_t arrayCountof(T(&)[N]) {return N;} 

*究其原因,函数的返回类型是一个数组的引用而不是一个数组,因为你不能返回数组。如果可以的话,任何选择都可以。

+2

+1 :)通过说'template typename identity :: type&arrayCountofHelper(T(&)[N]);':)我可以看到更好的整体虽然sizeof运算符的描述很奇怪,因为表达式从来没有引用类型,因为'5/6'(所以'sizeof'运算符得到的表达式的类型是'char [N]'),所以它应该指定“适用于引用类型时,结果是引用类型的大小” - 不提及引用。最后,由于引用闪耀,无论如何,它无所谓:) – 2010-05-31 20:37:05

+0

W哇,所以应该真的加上这个+100按钮:)谢谢! – 2010-06-01 08:19:02

2

奥伦

这不是一个函数引用。这是一个函数调用表达式,它有一个类型 - 结果的类型。 Sizeof可以应用于任何具有类型的表达式。