Can std :: start working with array parameters, and if so, how?

I have problems using std::begin() and std::end() (from the iterator library) with c-style array parameters.

 void SetOrigin(const double i_point[3]) { Vector v; std::copy( std::begin(i_point), std::end(i_point), v.begin()); this->setOrigin(v); } 

This results in the following error with Visual Studio 2010 (and similar for the end):

 error C2784: '_Ty *std::begin(_Ty (&)[_Size])' : could not deduce template argument for '_Ty (&)[_Size]' from 'const double []' 1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\xutility(995) : see declaration of 'std::begin' 

Changing the parameter to non-const gives the same result.

Attempt to specify a parameter as

 ... std::begin<const double, 3>(i_point), std::end<const double, 3>(i_point), ... 

gives:

 error C2664: '_Ty *std::begin<const double,3>(_Ty (&)[3])' : cannot convert parameter 1 from 'const double []' to 'const double (&)[3]' 

Is it possible to use std::begin for array parameters because they break into pointers? Is there a trick to get around this or is it best not to use the iterator functions on the array parameters?

+8
c ++ iterator arrays std stl
source share
5 answers

Yes, std::begin and std::end can work with parameters that are arrays of C. styles

The trick is to pass a parameter, which is an array of styles C. When you specify a 1D array as a normal parameter for a normal function, its type is quietly configured from the "array T" to "pointer to T". When you call this function, what is passed is not an array (like an array), but a pointer to the first element of the array.

However, you can pass an array by reference to a function template:

 template <class T, size_t N> void function(T (&array)[N]) { // function body here } 

In this case, when you pass the actual array (albeit by reference) and not a pointer, you can use std::begin and std::end perfectly. For example:

 template <class T, size_t N> T sum(T (&array)[N]) { return std::accumulate(std::begin(array), std::end(array), T()); } 

Now passing the array is trivial, for example:

 int array[] = {1, 2, 3, 4}; auto total = sum(array); 

std::begin and std::end themselves are implemented similarly to sum - the array is passed by reference, so they may look something like this:

 template <class T, size_t N> T *begin(T (&array)[N]) { return array; } template <class T, size_t N> T *end(T (&array)[N]) { return array + N; } 

Please note that although they were added to the standard quite recently, they do not require special use of templates, so the implementation above should work fine with the plain old C ++ 98 compiler (and, if memory serves, even with preliminary standard compilers such as VC ++ 6).

+14
source share

First of all, note that the declaration of the const double i_point[3] parameter is absolutely equivalent to const double* i_point . That is, the function accepts any pointer to double const regardless of the number of marked elements. As a result, he does not know the size, and std::begin() and std::end() cannot output the size (well, std::begin() really does not need to output the size anyway).

If you really want to use std::begin() and std::end() , you need to pass an array with three elements or a link to such a beast. Since you cannot pass arrays by value, it is best to pass it by reference:

 void SetOrigin(double const (&i_point)[3]) { // ... } 

This function accepts only arrays with exactly three elements as arguments: you cannot pass a pointer to three double or part of a larger array. In turn, you can use std::begin() and std::end() .

+4
source share
 void SetOrigin(const double i_point[3]) 

coincides with

 void SetOrigin(const double i_point[]) 

or

 void SetOrigin(const double *i_point) 

So std::begin and std::end cannot accept it. In C ++, you cannot pass an array, but as a pointer or reference. If it is a pointer, then it does not carry any information about the passed array.

Your alternatives are std::vector or std::array .

+1
source share

Have you looked at std :: array?

It works better with other STL components.

0
source share

Without directly answering your question ( M M. and Dietmar KΓΌhl have already answered enough), you want to initialize some std::vector in this function. However, why not just:

 std::vector v; std::copy(std::begin(x), std::end(x), std::back_inserter(v)); // or std::copy(x, x + 3, std::back_inserter(v)); 

Instead of calling a function of your function that is trying to do this?

Alternatively, you can write a function as follows:

 template<typename RandomIterator> void SetOrigin(RandomIterator start, RandomIterator end) { std::vector<int> v; std::copy(start, end, std::back_inserter(v)); SetOrigin(v); } 

and then call it using:

 double xyz[3]; SetOrigin(std::begin(xyz), std::end(xyz)); 
0
source share

All Articles