I have trouble 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 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 same result.
Trying to specify the 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 just not possible to use std::begin
on array parameters because they decay to pointers? Is there a trick to get around this or is it best just to not use the iterator functions on array parameters?
Yes, std::begin
and std::end
can work with parameters that are C style arrays.
The trick is in passing a parameter that's a C style array. When you specify a 1D array as a normal parameter to a normal function, its type is silently adjusted from "array of T" to "pointer to T". When you call that function, what gets passed isn't the array (as an array), but a pointer to the first element of the array.
It is, however, possible to 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, where you're passing an actual array (albeit, by reference) rather than a pointer, you can use std::begin
and std::end
perfectly well. 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 an array is trivial, such as:
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 can 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;
}
Note that although these were added to the standard more recently, they don't require any particularly tricky use of templates, so the implementation above should work fine with a plain old C++98 compiler (and, if memory serves, even with pre-standard compilers such as VC++ 6).
First off, note that the parameter declaration const double i_point[3]
is absolutely equivalent to const double* i_point
. That is, the function takes any pointer to double const
independent of the number of elements pointed to. As a result, it doesn't know the size and std::begin()
and std::end()
can't deduce the size (well, std::begin()
doesn't really need to deduce the size anyway).
If you really want to use std::begin()
and std::end()
you need to pass an array with three element or a reference to such a beast. Since you cannot pass arrays by value, your best bet is to pass it by reference:
void SetOrigin(double const (&i_point)[3]) {
// ...
}
This function only accepts arrays with exactly three elements as arguments: You cannot pass a pointer to three double
s or a part of a bigger array. In return, you can now use std::begin()
and std::end()
.
void SetOrigin(const double i_point[3])
is as same as
void SetOrigin(const double i_point[])
or
void SetOrigin(const double *i_point)
So, std::begin
and std::end
can not accept it. In C++ you can not pass an array but as a pointer or reference. If it's a pointer then it doesn't carry any information of passed array.
Your alternatives are std::vector
or std::array
.
Have you looked at std::array?
It works better with other STL components
While not directly answering your question (it has already been answered sufficiently by M M. and Dietmar Kühl), you appear to want to initialize some std::vector
in this function. That said, why not just have:
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 a function call to your function that is trying to do this?
Alternatively, you could write you function like this:
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));