std::begin 可以使用数组参数吗?如果可以,如何?

新手上路,请多包涵

我在使用带有 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'

将参数更改为非常量会产生相同的结果。

试图将参数指定为

...
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 因为它们衰减为指针?有没有办法解决这个问题,或者最好不要在数组参数上使用迭代器函数?

原文由 A.E. Drew 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.1k
2 个回答

是的, std::beginstd::end 可以 使用 C 样式数组的参数。

诀窍在于传递一个 C 样式数组的参数。当您将一维数组指定为普通函数的普通参数时,其类型会默默地从“T 数组”调整为“指向 T 的指针”。当您调用该函数时,传递的不是数组(作为数组),而是指向数组第一个元素的指针。

但是,可以通过引用函数模板来传递数组:

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

这种 情况下,如果您传递的是实际数组(尽管是通过引用)而不是指针,则可以使用 std::beginstd::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::beginstd::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 编译器上正常工作(并且,如果有记忆,即使使用 pre -标准编译器,例如 VC++ 6)。

原文由 Jerry Coffin 发布,翻译遵循 CC BY-SA 4.0 许可协议

首先,请注意参数声明 const double i_point[3] 绝对等同于 const double* i_point 。也就是说,该函数采用指向 double const 的任何指针,而与指向的元素数量无关。结果,它不知道大小和 std::begin()std::end() 无法推断出大小(嗯, std::begin() 确实不需要无论如何大小)。

如果你真的想使用 std::begin()std::end() 你需要传递一个包含三个元素的数组或对这种野兽的引用。由于您不能按值传递数组,因此最好的办法是通过引用传递它:

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

此函数仅接受具有恰好三个元素的数组作为参数:您不能将指针传递给三个 double 或更大数组的一部分。作为回报,您现在可以使用 std::begin()std::end()

原文由 Dietmar Kühl 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题