anony wrote:
The make_iterator_range() function sees only 2 pointers and these are
all it cares about. Now, let's check the standard:

ISO-IEC-14882 Section 8.3.4 Array, page 137:

An object of array type contains a contiguously allocated non-
empty set of N sub-objects of type T.
  
That's referring to a dimension 1 array explicitly, so doesn't have much bearing on this.  In particular a two dimension array data[2][2] is built by a compiler like this:

data[0] -=>[data[0][0]][data[0][1]]
data[1] -=>[data[1][0]][data[1][1]]

It's required by the standard, as you quoted, for data[0][0] and data[0][1] to be contiguous, for data[1][0] and data[1][1] to be contiguous, and also required for the pointers data[0] and data[1] to be contiguous (although their existence might get optimized away), but not AT ALL required for data[0][1] and data[1][0] (i.e. the two rows) to be contiguous.  i.e. data[0] could point at one chunk of memory for the first row, and data[1] can point at memory megabytes away and it will meet the requirements of the standard.  The compiler you're using chooses to allocate the memory for all the rows in one contiguous chunk, (at least some of the time as you discovered), so you get lucky at taking advantage of implementation defined behavior.  I wouldn't depend on it if I were you.
The pointers I provide point to the beginning and the end of the
vertices multidimensional array. The array must be contiguously
allocated, as specified in the standard, hence I don't see which aspect
of what I am doing in undefined, if the functions boost::begin() and
boost::end() work as expected (again, they return pointers, not fancy
iterator objects).

Did I mention the debugger shows everything is just perfect.
  
Yes, it shows what your compiler implements in this circumstance, but tells you nothing about what will be done by other compilers, or by your own compiler in all circumstances.   When you take advantage of implementation defined behavior, you're gambling with no guarantees except that if it fails it's your fault and you don't get to complain to the compiler implementor.
  
Why not just use BOOST_FOREACH correctly?

   BOOST_FOREACH(float (&rgf)[3], vertices)
     BOOST_FOREACH(float&  f, rgf)
       f *= scale;
        
Double loop, oops. Not fancy enough.
      
Are you joking?
    

I was looking for fancy (i.e. elegant) code, yours is too complicated.
  
It's pretty normal to use nested loops for nested elements, and prettily enough, you are dealing with each element, scaling it, so this is a perfect use of foreach.  I think it's quite elegant, both generating minimal assembler and being clear and maintainable.

Patrick