Something you seem to have overlooked when considering y-axis iteration is that there are many 'columns' down which you could iterate.
What you're trying to do is actually disregarde the 'column-identifier', which turns out to be the x-component, and this just isn't practical.
Side note:
You might wonder why you can disregard the y (or even z) components for iterating along the x-axis, the answer is that this largely down to the way that you've set up your nested vectors such that the x-axis vector is the vector that actually contains the data.So what can you do about this?
Well it turns out you have a few ways to solve this.
One way, which isn't entirely unreasonable I suppose, is to write custom iterators. This might make (more) sense if you wrapped those nested vectors into a new container class, call it CubeArray for example, then you can have a custom 3D iterator that you can access like normal: CubeArray<T>::iterator.
Writing iterators isn't hard, you just need to provide some technique to... well... iterate. Depending on the function that you provide your iterator can be a forwards iterator, backwards iterator, random access iterator etc.
If you're interested in writing STL compliant iterators then you need to adhere to their interface requirements. For example
here you can find the details of a bi-directional iterator, if you provide a class with those functions then it's a fully compliant iterator.
However,
Other solutions certainly do exist; one way might be to condense your container down into a single vector:
vector<T> myArray
Note: You might actually gain some efficiency from a single vector, but that's not why I'm suggesting it.You can still pretend this is a 3-dimensional array if you know the width, height and depth, although actually you don't need the depth for accessing elements:
myArray[(z * height + y) * width + x]
This now means that all mutable iterators will be of type vector<T>::iterator.
In order to allow the doBlur function to do its job it needs to be augmented with an offset argument; it must now also require that its iterators be random-access iterators (vector iterators are random access, so it's fine).
This offset argument (occasionally called the 'pitch', I think) is the offset from one element to the next.
So (if),
the x-axis components are contiguous, it's an offset of: 0,
the y-axis components are width distance apart, it's an offset of: width,
the z-axis components are width * height distance apart, it's an offset of: width * height.
To see this in action:
template <class RandomAccessIter>
void doBlur(RandomAccessIter xIterBegin, RandomAccessIter xIterEnd, int offset);
vector<T>::iterator yIterBegin = myArray.begin() + ((z1 * height + y1) * width + x1);
vector<T>::iterator yIterEnd = myArray.begin() + ((z2 * height + y2) * width + x2);
int offset = width;
doBlur(yIterBegin, yIterEnd, offset);
It would probably do to write a utility function to return the iterator at a given x, y, z position.