编译时 sizeof_array 不使用宏
这只是过去几天困扰我的事情,我认为不可能解决,但我以前见过模板魔法。
如下:
要获取标准 C++ 数组中的元素数量,我可以使用宏 (1) 或类型安全内联函数 (2):
(1)
#define sizeof_array(ARRAY) (sizeof(ARRAY)/sizeof(ARRAY[0]))
(2)< /strong>
template <typename T>
size_t sizeof_array(const T& ARRAY){
return (sizeof(ARRAY)/sizeof(ARRAY[0]));
}
正如你所看到的,第一个存在作为宏的问题(目前我认为这是一个问题),另一个存在无法在编译时获取数组大小的问题;即我不能写:
enum ENUM{N=sizeof_array(ARRAY)};
或者
BOOST_STATIC_ASSERT(sizeof_array(ARRAY)==10);// Assuming the size 10..
有谁知道这是否可以解决?
更新:
此问题是在引入 constexpr 之前创建的。现在你可以简单地使用:
template <typename T>
constexpr auto sizeof_array(const T& iarray) {
return (sizeof(iarray) / sizeof(iarray[0]));
}
This is just something that has bothered me for the last couple of days, I don't think it's possible to solve but I've seen template magic before.
Here goes:
To get the number of elements in a standard C++ array I could use either a macro (1), or a typesafe inline function (2):
(1)
#define sizeof_array(ARRAY) (sizeof(ARRAY)/sizeof(ARRAY[0]))
(2)
template <typename T>
size_t sizeof_array(const T& ARRAY){
return (sizeof(ARRAY)/sizeof(ARRAY[0]));
}
As you can see, the first one has the problem of being a macro (for the moment I consider that a problem) and the other one has the problem of not being able to get the size of an array at compile time; ie I can't write:
enum ENUM{N=sizeof_array(ARRAY)};
or
BOOST_STATIC_ASSERT(sizeof_array(ARRAY)==10);// Assuming the size 10..
Does anyone know if this can be solved?
Update:
This question was created before constexpr was introduced. Nowadays you can simply use:
template <typename T>
constexpr auto sizeof_array(const T& iarray) {
return (sizeof(iarray) / sizeof(iarray[0]));
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
请尝试此处执行以下操作:
它应该打印出来: “数组计数为:10”
Try the following from here:
It should print out: "The array count is: 10"
在 C++1x 中
constexpr
将为您提供:In C++1x
constexpr
will get you that:我能想到的最好的办法是:
它必须与另一个
sizeof
一起使用:[EDIT]
想想看,我相信这在除了宏之外,C++03 中还有一个“类似函数的调用”,原因如下。
一方面,您显然需要模板参数推导来获取数组的大小(直接或通过
sizeof
来获取数组的大小)。但模板参数推导仅适用于函数,不适用于类;即,您可以拥有一个引用类型为 N 的数组的模板参数 R,其中 N 是另一个模板参数,但您必须在调用时同时提供 R 和 N;如果你想从 R 中推导出 N,只有函数调用可以做到这一点。另一方面,涉及函数调用的任何表达式可以保持常量的唯一方式是当它位于
sizeof
内部时。其他任何事情(例如,访问函数返回值上的静态或枚举成员)仍然需要进行函数调用,这显然意味着这不会是常量表达式。The best I can think of is this:
which has to be used with another
sizeof
:[EDIT]
Come to think of it, I believe this is provably impossible to do in a single "function-like call" in C++03, apart from macros, and here's why.
On one hand, you will clearly need template parameter deduction to obtain size of array (either directly, or via
sizeof
as you do). However, template parameter deduction is only applicable to functions, and not to classes; i.e. you can have a template parameter R of type reference-to-array-of-N, where N is another template parameter, but you'll have to provide both R and N at the point of the call; if you want to deduce N from R, only a function call can do that.On the other hand, the only way any expression involving a function call can be constant is when it's inside
sizeof
. Anything else (e.g. accessing a static or enum member on return value of function) still requires the function call to occur, which obviously means this won't be a constant expression.这并不完全是您正在寻找的内容,但它很接近 - 来自
winnt.h
的片段,其中包括对 #$%^ 它正在做什么的一些解释:RTL_NUMBER_OF_V2() 宏最终被用在更具可读性的
ARRAYSIZE()
宏中。Matthew Wilson 的“不完美的 C++” 书中还讨论了以下技术:在这里使用。
It's not exactly what you're looking for, but it's close - a snippet from
winnt.h
which includes some explanation of what the #$%^ it's doing:The
RTL_NUMBER_OF_V2()
macro ends up being used in the more readableARRAYSIZE()
macro.Matthew Wilson's "Imperfect C++" book also has a discussion of the techniques that are used here.
我喜欢的问题
Adisak的答案
: Microsoft 用于 _countof 宏 在 VS2008 中,它有一些不错的功能:
但正如 Georg 所指出的,这种方法使用模板,所以它不保证能够使用 C++03 的本地类型:
幸运的是,我们不祝你好运。
解决方案
Ivan Johnson 提出了一个聪明的方法,它适用于所有帐户:它是类型安全的,编译时,并适用于本地类型:
对于那些感兴趣的人,它的工作原理是在标准的基于 sizeof 的数组大小宏之前插入两个“测试”。这些测试不会影响最终计算,但旨在生成非数组类型的编译错误:
arr
是整数、枚举、指针或数组,否则第一个测试将失败。对于任何其他类型,reinterpret_cast
应该失败。对于整型、枚举或指针类型,第二个测试失败。
整数和枚举类型将失败,因为
check_type
没有与它们匹配的版本,因为check_type
需要指针。指针类型将失败,因为它们将与
check_type
的模板化版本匹配,但模板化check_type
的返回类型 (Is_pointer
)不完整,会产生错误。数组类型将通过,因为采用
T
类型数组的地址会给你
T (*)[]
,又名指向数组的指针,而不是指向指针的指针。这意味着check_type
的模板化版本将不匹配。感谢 SFINAE,编译器将转向check_type 的非模板化版本
,它应该接受任何一对指针。由于非模板化版本的返回类型已完全定义,因此不会产生错误。由于我们现在不处理模板,因此本地类型可以正常工作。The Problem
I like Adisak's answer:
It's what Microsoft uses for the _countof macro in VS2008, and it's got some nice features:
But as pointed out by Georg, this approach uses templates, so it's not guaranteed to work with local types for C++03:
Fortunately, we're not out luck.
The Solution
Ivan Johnson came up with a clever approach that wins on all accounts: it's typesafe, compile-time, and works with local types:
For those who are interested, it works by inserting two "tests" before the standard sizeof-based array-size macro. Those tests don't impact the final calculation, but are designed to generate compile errors for non-array types:
arr
is integral, enum, pointer, or array.reinterpret_cast<const T*>
should fail for any other types.The second test fails for integral, enum, or pointer types.
Integral and enum types will fail because there's no version of
check_type
that they match, sincecheck_type
expects pointers.Pointer types will fail because they'll match the templated version of
check_type
, but the return type (Is_pointer
) for the templatedcheck_type
is incomplete, which will produce an error.Array types will pass because taking the address of an array of type
T
will give you
T (*)[]
, aka a pointer-to-an-array, not a pointer-to-a-pointer. That means that the templated version ofcheck_type
won't match. Thanks to SFINAE, the compiler will move on to the non-templated version ofcheck_type
, which should accept any pair of pointers. Since the return type for the non-templated version is defined completely, no error will be produced. And since we're not dealing with templates now, local types work fine.如果您使用的是仅限 Microsoft 的平台,则可以利用
以下工作正常(VS 2008 RTM),
但同样,它是 MS 特定的,因此这可能不适合您。
If you are on a Microsoft only platform, you can take advantage of the _countof macro. This is a non-standard extension which will return the count of elements within an array. It's advantage over most countof style macros is that it will cause a compilation error if it's used on a non-array type.
The following works just fine (VS 2008 RTM)
But once again, it's MS specific so this may not work for you.
一般来说,您无法解决它,这就是像 boost array(当然还有 stl 风格的行为)。
You can't solve it in general, thats one the reasons for array wrappers like boost array (plus stl-style behaviour of course).
如果没有当前 C++ 标准的宏,似乎不可能将 sizeof 数组作为编译时常量获取(您需要一个函数来推断数组大小,但在需要编译时常量的地方不允许函数调用) 。 [编辑:但是看看 Minaev 的出色解决方案!]
但是,您的模板版本也不是类型安全的,并且遇到与宏相同的问题:它也接受指针,特别是衰减为指针的数组。当它接受指针时,sizeof(T*) / sizeof(T) 的结果没有意义。
更好的:
It appears not to be possible to obtain the sizeof array as a compile-time constant without a macro with current C++ standard (you need a function to deduce the array size, but function calls are not allowed where you need a compile-time constant). [Edit: But see Minaev's brilliant solution!]
However, your template version isn't typesafe either and suffers from the same problem as the macro: it also accepts pointers and notably arrays decayed to a pointer. When it accepts a pointer, the result of sizeof(T*) / sizeof(T) cannot be meaningful.
Better:
如果没有 C++0x,我能得到的最接近的是:
它要么给你一个可以传递变量的函数,要么给你一个也可以传递类型的模板。您不能将该函数用作编译时常量,但大多数情况下您知道该类型,即使仅作为模板参数。
Without C++0x, the closest I can get is:
which either gives you a function you can pass the variable to, or a template you can pass the type too. You can't use the function for a compile time constant, but most cases you know the type, even if only as template parameter.
现在,STL 库可用于决定/选择数组大小编译时
输出:
3
Now STL libraries are available to decide/select array size compile time
Output:
3