我正在尝试使用Android AOSP键盘源作为模型开发Android键盘。有相当多的JNI代码,我的C ++有点生疏,我对宏NELEMS
的以下定义有困难:
// Disclaimer: You will see a compile error if you use this macro against a variable-length array.
// Sorry for the inconvenience. It isn't supported.
template <typename T, int N>
char (&ArraySizeHelper(T (&array)[N]))[N];
#define NELEMS(x) (sizeof(ArraySizeHelper(x)))
当我尝试编译时,此代码的第二行(位于#define
上方)会亮起并显示错误:
引用变量声明需要初始值设定项
错误信息对我有意义; AOSP代码没有。符号ArraySizeHelper
在AOSP代码或make文件中没有出现(也就是说,据我所知,它不是其他东西的宏)。
从宏的名称,我猜它应该评估数组中的元素数量。据我所知,通常的做法是:
#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
所以我想知道是否还有其他事情发生了。
我很欣赏这段代码应该做什么的解释以及如何处理编译错误的指导。
编辑:我正在通过Android Studio 1.3 RC 3,Android NDK r10e和Gradle 2.5进行编译。编译使用各种工具链(如this Android documentation中所述)。奇怪的是,上面的代码现在可以正确编译和执行(也许它总是这样)。但是,Android studio仍会在该行上显示错误。每次使用NELEMS
时都会显示错误:
宏替换后出错:参数太多,预期为0
我现在认为这是IDE代码分析错误,而不是编译器或编码问题。我最初的问题是关于代码本身,所以我将这个帖子标记为已回答。我将打开另一个关于什么似乎是IDE问题的问题。感谢大家的解释!
答案 0 :(得分:4)
代码的目的是安全地获得可在编译时使用的数组大小,例如:作为新的原始(非动态)数组的大小。
简单定义
#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
...是不安全的,因为你可以传递指针,然后回到无意义的大小。
所以你拥有的代码,
template <typename T, int N>
char (&ArraySizeHelper(T (&array)[N]))[N];
#define NELEMS(x) (sizeof(ArraySizeHelper(x)))
...使用模板参数推导来查找大小,并使用引用数组返回类型将大小报告为编译时常量。如果不是在C ++ 11及之后关于传递引用的(1)愚蠢的措辞,我们现在可以对constexpr
做同样的事情。唉,为了获得编译时数组大小的简单任务,我们可能必须等到C ++ 17才能完全避免使用宏。
我无法重现这个问题;以下代码:
template <typename T, int N>
char (&ArraySizeHelper(T (&array)[N]))[N];
#define NELEMS(x) (sizeof(ArraySizeHelper(x)))
#include <iostream>
auto main() -> int
{
using namespace std;
int x[42];
cout << NELEMS( x ) << endl;
}
可以很好地编译Visual C ++ 2015和MinGW-64 g ++ 5.1.0。
1) C ++14§5.19/ 2“A 条件表达式 e
是核心常量表达式,除非评估e
,遵守规则
抽象机器(1.9),将评估以下表达式之一:[...] - 一个 id-expression ,它引用引用类型的变量或数据成员,除非引用具有先前的初始化并且
- 用常量表达式初始化或
- 它是一个对象的非静态数据成员,其生命周期始于e
的评估范围内;
功能
答案 1 :(得分:4)
此:
template <typename T, int N>
char (&ArraySizeHelper(T (&array)[N]))[N];
声明一个名为ArraySizeHelper
的函数,该函数引用一个名为N
的{{1}} T
数组,并返回对array
数组的引用。没有给出定义。
char[N]
不需要定义函数 - 它的操作数未被评估。它只对类型进行操作:如果sizeof()
的类型为sizeof(ArrayHelper(x))
,则sizeof(char[N])
会对x
进行评估(否则无法编译)。
这也是一种非常复杂的写作方式:
T[N]
这远比容易理解。并且不需要宏。