C++和预处理宏注意事项

4

你能找出下面语句的错误吗?

GCC错误提示:

声明为返回数组的函数'type name'

#define MACRO(a) (a)[1]

class index {
public:
    typedef int index_type[2];
    const index_type& operator[](int i) const;
};

int k = 0;
int i = MACRO(index()[k]);

顺便说一句:我知道出了什么问题,我觉得这是一个有趣的事情可以分享。非常感谢litb,他之前的解释帮助我相当快地解决了这个错误。


2
你可以编辑它们。 - Michael Mrozek
1
那段代码在我的Visual C++ 2008中编译通过(尽管我不得不将“class”更改为“struct”以使成员公开...在顶部添加“public:”也会达到同样的效果)。我猜你在“int i = MACRO(...”这一行上遇到了错误? - Dean Harding
嗯,在VS中可以运行,但在gcc中无法运行。奇怪。我不明白为什么会失败。而且,这个问题到底为什么被踩了? - GManNickG
@codeka 是的。除非我再次搞砸了,否则你应该会收到错误。 也许 VS 不符合标准?上面的示例是对我有用的简化代码片段。 - Anycorn
1
顺便说一句,@GMan,这是cw,因为我知道答案(花了我一些时间才找到),而且我觉得这很有趣。 - Anycorn
显示剩余4条评论
3个回答

4
在扩展行中:
int i = (index()[k])[1];

(index()[k]) 被解释为一个强制类型转换表达式,声明了一个返回长度为 k 的 index 数组的函数。至少看起来是这样的。如何让 gcc 有效地将 [1] 解释为一个表达式,我不确定。


英译中:Intel 编译器和 Visual C++ 编译器。我认为它们使用相同的前端。 - Anycorn
2
@aaa:Intel C++编译器使用EDG前端,而Microsoft Visual C++则使用自己的前端。它们完全没有关联。 - James McNellis

2

我猜测你的语法存在歧义。编译器可能正在查看扩展的宏:

 int i = (index()[k])[1];

我猜想index实际上是一个非成员函数声明,返回一个数组,而不是构造一个临时对象类型index

但这只是我的猜测...如果你已经知道答案,请给我们指点 :)


是的,这就是正在发生的事情(好吧,至少这是我解释的方式)。 - Anycorn
顺便说一句,我认为这可以解释为什么Visual C++可以编译它并且仍然被认为是“符合标准”的。由于存在模棱两可的语法,编译器可以选择以任何方式解释它,并且仍然被认为是“符合标准”的 :) - Dean Harding
我害怕想,标准库中可能定义了这样的行为。 - Anycorn

1
在应用宏后,它会展开为以下内容:
class index 
{
    // ...
    typedef int index_type[2];
    const index_type& operator[](int i)const;
    // ...
};

int k = 0;
int i = (index()[k])[1];

现在的问题是(假设index :: operator []是公共的,并且从您的代码片段中无法明显),index :: operator []的结果是通过引用返回的,而您正在将index()对象构造为临时对象,因此,假设您的index :: operator []实现了我猜测的方式(返回成员对象的引用),则index :: operator []的结果将在返回后立即无效(因为临时对象被销毁),因此您具有未定义的行为。

起初我也是这么想的,但并不完全正确。我加上了const限定符以消除歧义。 - Anycorn
即使有const限定符,@aaa仍然是一个引用。 - Michael Aaron Safyan
在所呈现的代码中没有任何未定义行为。(这也无法解释错误。)返回成员的引用是可以的,临时变量会一直存在到完整表达式结束。 - GManNickG
@GMan,你是对的。那是一个打字错误。 - Michael Aaron Safyan
1
你的预处理器扩展并不完全正确。语法错误藏在其中。好的,现在它是正确的了。 - Anycorn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接