Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is the address of an array element sometimes mistaken for a declaration?

I have some user defined iterators, and every now and then I get a strange error that is easy to work around, but I don't understand why I'm getting it:

uint8_t bytes[pitch*height];

array_iterator::col_iterator a( &bytes[0] );

array_iterator::row_iterator base_iter_begin(
  array_iterator::col_iterator( &bytes[0] ), width, pitch );

array_iterator::row_iterator base_iter_end(
  array_iterator::col_iterator( &bytes[pitch*height] ), width, pitch
  );

I have a class called array_iterator with embedded typedefs row_iterator and col_iterator. The row_iterator constructor takes a col_iterator as its first argument. The first and last statement work just fine. The middle statement fails to compile with the following error:

test-2d-iterators.cc:780: error: declaration of 'bytes' as array of references

Writing &( bytes[0] ) doesn't solve the problem (not surprisingly, since [] has higher precedence than &). Of course, I can just substitute "a" for the explicit col_iterator constructor call, but why do I have to? And if there is a problem, why does the col_iterator constructor in the last line compile?

Thanks.

like image 429
user1806566 Avatar asked Nov 02 '22 23:11

user1806566


1 Answers

First of all, we can narrow down your problem to the following lines:

struct row_iterator { ... };
typedef unsigned* col_iterator;
unsigned bytes[5];
row_iterator base_iter_begin(col_iterator(&bytes[0]));

And the third line is understood as:

row_iterator base_iter_begin(col_iterator& bytes[0]);

And that one line declares a function taking as parameter an array of 0 references to col_iterator and returning an int. It is indeed a case of most vexing parse as pointed out in the comments.

The simplest way to get rid of it is to use copy initialization instead of direct initialization (initialization in C++):

row_iterator base_iter_begin = row_iterator(col_iterator(&bytes[0]));

Which in your case would be:

array_iterator::row_iterator base_iter_begin = array_iterator::row_iterator(array_iterator::col_iterator( &bytes[0] ), width, pitch );

NOTE: Provided you are using C++11, there are even more initialization rules, and you can use list initialization to get rid of both the boilerplate and the most vexing parse:

array_iterator::row_iterator base_iter_begin{array_iterator::col_iterator(&bytes[0]), width, pitch};
like image 122
Morwenn Avatar answered Nov 08 '22 04:11

Morwenn