我在使用带有c样式数组参数的std::begin()
和std::end()
(来自iterator
库)时遇到问题。
void SetOrigin(const double i_point[3]) {
Vector v;
std::copy(
std::begin(i_point),
std::end(i_point),
v.begin());
this->setOrigin(v);
}
这会导致Visual Studio 2010出现以下错误(类似于结束):
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'
将参数更改为非const会产生相同的结果。
尝试将参数指定为
...
std::begin<const double, 3>(i_point),
std::end<const double, 3>(i_point),
...
给出:
error C2664: '_Ty *std::begin<const double,3>(_Ty (&)[3])' : cannot convert parameter 1 from 'const double []' to 'const double (&)[3]'
是否只能在数组参数上使用std::begin
,因为它们会衰减为指针?有没有解决这个问题的技巧,或者最好不要在数组参数上使用迭代器函数?
答案 0 :(得分:17)
是的,std::begin
和std::end
可以使用C样式数组的参数。
诀窍在于传递一个C样式数组的参数。当您将1D数组指定为普通函数的正常参数时,其类型将从“数组T”静默调整为“指向T”。当你调用那个函数时,传递的不是数组(作为数组),而是指向数组第一个元素的指针。
但是,可以通过引用函数模板来传递数组:
template <class T, size_t N>
void function(T (&array)[N]) {
// function body here
}
在这个的情况下,你传递的是一个实际的数组(尽管是通过引用而不是指针),你可以很好地使用std::begin
和std::end
。例如:
template <class T, size_t N>
T sum(T (&array)[N]) {
return std::accumulate(std::begin(array), std::end(array), T());
}
现在传递一个数组是微不足道的,例如:
int array[] = {1, 2, 3, 4};
auto total = sum(array);
std::begin
和std::end
本身的实现与sum
类似 - 数组通过引用传递,因此它们看起来像这样:
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;
}
请注意,虽然最近这些已添加到标准中,但它们并不需要任何特别棘手的模板使用,因此上面的实现应该可以使用普通的旧C ++ 98编译器(并且,如果内存服务,即使使用VC ++ 6等预标准编译器。
答案 1 :(得分:4)
首先请注意,参数声明const double i_point[3]
绝对等同于const double* i_point
。也就是说,该函数接受指向double const
的任何指针,与指向的元素数量无关。因此,它不知道大小,而std::begin()
和std::end()
无法推断出大小(好吧,std::begin()
无论如何都不需要推断大小。)< / p>
如果你真的想使用std::begin()
和std::end()
,你需要传递一个包含三个元素的数组或对这样一个野兽的引用。由于您无法按值传递数组,因此最好将其通过引用传递:
void SetOrigin(double const (&i_point)[3]) {
// ...
}
此函数仅接受具有三个元素作为参数的数组:您不能将指针传递给三个double
或更大数组的一部分。作为回报,您现在可以使用std::begin()
和std::end()
。
答案 2 :(得分:1)
void SetOrigin(const double i_point[3])
与
相同void SetOrigin(const double i_point[])
或
void SetOrigin(const double *i_point)
因此,std::begin
和std::end
无法接受。在C ++中,您不能传递数组,而是作为指针或引用。如果它是一个指针,那么它不会携带传递数组的任何信息。
您的替代方案是std::vector
或std::array
。
答案 3 :(得分:0)
你看过std :: array吗?
与其他STL组件一起使用效果更好
答案 4 :(得分:0)
虽然没有直接回答您的问题(M M.和Dietmar Kühl已经对其进行了充分的回答),但您似乎想在此函数中初始化一些std::vector
。那说,为什么不只是:
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));
而不是试图执行此功能的函数调用?
或者,你可以写下这样的函数:
template<typename RandomIterator>
void SetOrigin(RandomIterator start, RandomIterator end)
{
std::vector<int> v;
std::copy(start, end, std::back_inserter(v));
SetOrigin(v);
}
然后使用:
调用它double xyz[3];
SetOrigin(std::begin(xyz), std::end(xyz));