views:

140

answers:

3

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

+1  A: 

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
my thoughts at first. but not quite the answer. I put const qualifier to disambiguate
aaa
@aaa, it is still a reference, even with a const qualifier.
Michael Aaron Safyan
There isn't any undefined behavior in the presented code. (Which wouldn't explain the error anyway.) Returning a reference to a member would be fine, the temporary lives until the end of the full expression.
GMan
@GMan, you are right. That's a typo.
Michael Aaron Safyan
your preprocessor expansion is not quite right. the syntax error is hidden in there. okay, now it's right.
aaa
+2  A: 

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
yes, that is what is happening (well, at least this is how i explained it).
aaa
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
am afraid to think that somewhere in standard such behavior is defined.
aaa
+5  A: 

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
Intel compiler and visual C++ compile. I think they use the same front-end
aaa
@aaa: The Intel C++ Compiler uses the EDG frontend; Microsoft Visual C++ uses its own frontend. They are entirely unrelated.
James McNellis