5

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.

fredoverflow
  • 256,549
  • 94
  • 388
  • 662
user1806566
  • 1,078
  • 6
  • 18
  • 2
    Most Vexing Parse maybe? – Mooing Duck Apr 26 '13 at 01:52
  • 1
    Post a *short* example that repros the problem. – Michael Burr Apr 26 '13 at 02:20
  • It could be the Most Vexing Parse, but I'm not sure. Wouldn't the third line parse the same way? static_cast( &bytes[0] ) solves the problem, but just adding parens around &bytes[0] does not. Sorry the example isn't more distilled, but the problem seems to come and go with no rhyme or reason (i.e., how is the third line different from the second?), so it has resisted my attempts. It certainly looks like a parse error, though, so I would think it doesn't depend on what row_iterator or col_iterator actually are. – user1806566 Apr 26 '13 at 03:10
  • Can you turn this into a [SSCCE](http://www.sscce.org/)? Drop the containing `array_iterator` class, drop all functionality except constructors, and see whether the problem remains, and if not, when it vanishes. If it remains, post remaining code, that shouldn't be too much. – MvG Apr 26 '13 at 07:11

1 Answers1

2

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};
Morwenn
  • 21,684
  • 12
  • 93
  • 152