4

Can you figure out what is wrong with the statement below?

GCC error states:

'type name' declared as function returning array

#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]);

btw: I know what is wrong, I thought it was amusing thing to share. Many thanks to litb, his explanation of previous gotcha helped to solve this error pretty quickly.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Anycorn
  • 50,217
  • 42
  • 167
  • 261
  • sorry, I messed up previous post – Anycorn Apr 30 '10 at 01:25
  • 2
    You can [edit](http://stackoverflow.com/posts/2741790/edit) them – Michael Mrozek Apr 30 '10 at 01:27
  • 1
    That code compiles for me in Visual C++ 2008 (though I had to change `class` to `struct` to make the members public... adding `public:` at the top would've done the same thing). I assume you get the error on the `int i = MACRO(...` line? – Dean Harding Apr 30 '10 at 01:29
  • I would just add that I hope you're not planning on use this sort of code in a real situation! – Dean Harding Apr 30 '10 at 01:30
  • Hm, works in VS, doesn't work in gcc. Strange. I don't see why it should be failing. Also, *why on Earth is this being down-voted?* – GManNickG Apr 30 '10 at 01:30
  • @codeka yes. you should be getting error, unless I messed up again. maybe VS is not standard compliant? the above example is simplified snippet of code useful to me – Anycorn Apr 30 '10 at 01:30
  • It's fixed if you changed the macro to #define MACRO(a) a[1], but I don't know enough C++ syntax to understand why, so if somebody can run with that and post an answer, go for it – Michael Mrozek Apr 30 '10 at 01:33
  • 1
    @GMan by the way, this is cw because I know answer ( took me some time to find) and I thought it was amusing – Anycorn Apr 30 '10 at 01:35
  • @aaa: Ah, I see. Well I can't wait to see then, because I don't see it. :X – GManNickG Apr 30 '10 at 01:36

3 Answers3

4

In the expanded line:

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

(index()[k]) is interpreted as a cast expression, declaring a function that returns an array of length k of index. At least, that's what it looks like is happening. How gcc is manages to validly interpret the [1] as an expression, I'm not sure.

outis
  • 75,655
  • 22
  • 151
  • 221
2

My guess would be there's an ambiguity in your syntax. The compiler might be looking at the expanded macro:

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

And thinking that index is actually a non-member function declaration that returns an array, rather than construction of a temporary object of type index.

But that's just a guess... if you know the answer already, please enlighten us :)

Dean Harding
  • 71,468
  • 13
  • 145
  • 180
  • yes, that is what is happening (well, at least this is how i explained it). – Anycorn Apr 30 '10 at 01:49
  • By the way, I think this would explain why Visual C++ can compile it and still be considered "standards compliant". With an ambiguous syntax, the compiler can choose to interpret it either way and still be considered "standards compliant" :) – Dean Harding Apr 30 '10 at 01:54
  • am afraid to think that somewhere in standard such behavior is defined. – Anycorn Apr 30 '10 at 01:56
1

When you apply your macro, it expands to:

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

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

Now the problem (assuming that index::operator[] is public, and it is non-obvious from your code snippet that it is) is that the result of index::operator[] is returned by reference, and you are constructing the index() object as a temporary, and so, assuming your index::operator[] is implemented how I'm guessing you've implemented it (returning a reference to a member object), the result of index::operator[] will be invalid immediately after it is returned (as the temporary is destructed), and so you have undefined behavior.

Michael Aaron Safyan
  • 93,612
  • 16
  • 138
  • 200