为了找到一种方法来为c风格的数组做一个便携,安全的元素计数,我找到了这个解决方案:
template <typename T, unsigned N> char (&arrayCountofHelper(T(&)[N]))[N];
#define ARRAY_COUNTOF(arr) (sizeof(arrayCountofHelper(arr)))
似乎arrayCountofHelper实际上是对函数的引用,而宏ARRAY_COUNTOF使用的函数是函数的大小是它返回类型的大小。
它工作得很好。
但是,当我试图检查它是否便携时,我没有找到任何证据。我在标准(14882/1998)中找不到对sizeof(函数引用)的任何引用,事实上,我不能完全确定我甚至不能创建函数引用(尽管标准确实提到了几个)次)。
那么,有人知道我应该看哪个标准吗? (或者,如果我误解了声明的一些方法,那么正确的解释是什么?)
感谢
奥伦
P.S。 (对于那些认为我没有为我的问题找到合适解决方案的人) 我知道我总是可以使用
#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 :: array或std :: vector,但这是我维护的遗留代码)
答案 0 :(得分:4)
我们将松散地选择这个,我使用INCITS + ISO + IEC + 14882-2003。我会引用一些小东西,但是一些比较复杂的东西太大而无法引用。
sizeof
在§5.3.3中定义,它表示(删节):
sizeof运算符产生其操作数的对象表示中的字节数。操作数是表达式(未计算)或带括号的type-id。
换句话说,它以字节为单位生成一个类型的大小,或者查找表达式的类型并生成其大小。我们没有类型,我们有表达式arrayCountofHelper(arr)
。
您可以通过分别查看§5.1和§5.2中定义的primary-expression
和postfix-expression
的定义来剖析此表达式。您会发现它是postfix-expression
并符合函数调用的要求(§5.2.2)。
现在回到sizeof
。我们只关心这个函数调用表达式的类型(所以我们可以得到它的大小),§5.2.2/ 3说:
函数调用表达式的类型是静态选择函数的返回类型[...]。此类型应为完整的对象类型,引用类型或类型
void
。
因此我们需要使用arrayCountofHelper(arr)
找到要调用的函数的返回类型(记住,这都是未评估的)。 arrayCountofHelper
是一个我们将要实例化的函数模板(§14.7),所以我们需要在实例化函数获取返回类型之前执行此操作。
所有模板参数都需要有值(§14.8.2),并且通过使用§14.8.2.1中定义的规则,我们将通过匹配传递给它的数组来找到T
和N
。函数与函数参数(它是对数组的引用)。 (例如,如果arr
为int[10]
,则T
为int
,N
为10.)一旦我们拥有这些功能,就可以实例化该功能
实例化后,函数的返回类型为char(&)[N]
*,即对N
char
数组的引用。 (如果需要帮助解析,请参阅§8.3.5。关于如何解析“复杂”类型的SO也有问题。)所以现在我们已经找到了表达式的类型,我们必须考虑它的大小。 / p>
§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;}
*函数返回类型是对数组的引用而不是数组的原因仅仅是因为您无法返回数组。如果可以的话,任何一种选择就足够了。
答案 1 :(得分:2)
奥伦
这不是功能参考。这是一个函数调用表达式,它有一个类型 - 结果的类型。 Sizeof可以应用于任何具有类型的表达式。