这段代码发生了什么?

时间:2015-07-21 19:26:37

标签: c++ templates android-ndk

我正在尝试使用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问题的问题。感谢大家的解释!

2 个答案:

答案 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]

这远比容易理解。并且不需要宏。