3

With C arrays, it is fairly easy to write code that takes arrays of any size:

void func( T* itBegin, T* itEnd );

void main() {
    T arr1[1];
    func( std::begin(arr1), std::end(arr1) );
    T arr2[2];
    func( std::begin(arr2), std::end(arr2) );
}

How can I do that with std::arrays?

void func( ??? itBegin, ??? itEnd );

void main() {
    std::array<T,1> arr1;
    func( std::begin(arr1), std::end(arr1) );
    std::array<T,2> arr2;
    func( std::begin(arr2), std::end(arr2) );
}

The problem is that, in MSVC 2010, std::array<T,N>::iterator is different for different N. Is this a bug in MSVC 2010? If not, what is the rationale of this design? Yes, I could get pointers from the std::array and pass them instead of iterators, but isn't that unnecessarily ugly?

BTW, boost::array<T,N>::iterator are the same for all N.

3
  • What do you mean by "without template"? Commented Apr 17, 2012 at 10:13
  • void func( T* itBegin, T* itEnd ) is already a templated function, so I cannot se how can you comply with that "without template" requirement. Commented Apr 17, 2012 at 10:32
  • @Gorpik: Well, no, it isn't templated. It just uses a type with the unfortunate name T. See main, which also uses T and cannot be templated. Commented Apr 17, 2012 at 11:27

3 Answers 3

4
template <class I>
void func(I begin, I end)
{
    for (auto x = begin; x != end; ++x)
        something_with(*x);
}

Define them genericly as a type parameter, and then just use them as if they were pointers. Anything that behaves pointer-like will compile, things that don't, won't.

Pointer-like things include normal pointers, as well as standard library iterators, and anything else that defines operator=, operator* and operator++.

Doing it this way and as you will only ever use matching pairs of begin/end iterator ranges from the same array<N>, then it doesn't matter if array<N>::iterator is a different type to array<M>::iterator.

Sign up to request clarification or add additional context in comments.

2 Comments

I know it is easy with a template. But virtual functions, for example, cannot be templates, and templates have to be defined in the header. There is no technical reason why a template is needed.
@Arno: Type parameters is the C++ idiom for passing iterators. If you're not comfortable with templates, you are going to be miserable using the standard library.
2

As far as I can tell, the standard doesn't require that different sized std::array have the same type of iterator; having a different type for std::array<int, 1> and std::array<int, 2> seems legal (although one might have some opinions with regards to the quality of the implementation).

If this is a problem, you can either use a C style array, or use pointers:

func( &arr1[0], &arr1[0] + arr1.size() );

Neither solution is ideal, but they're the best I can offer.

4 Comments

&*begin(arr1), &*end(arr1) ? Might look bizarre at first glance, but should be a common technique with iterators, smart pointers.
Well, it only works if the underlying memory block is contiguous and compact, which it is for array and vector, but of course not in general.
@Arno: The longer syntax in the answer also requires that.
@Arno Yes, but his problem is uniquely with std::array. (Of course, if you're going to do this a lot, I'd suggest an overloaded begin and end, which do this for an std::array, and forward to std::begin and std::end for anything else.)
0
template <class I>
void func(I begin, I end);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.