可以std :: begin使用数组参数,如果可以,怎么做?

时间:2013-11-18 22:47:02

标签: c++ arrays stl iterator std

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

5 个答案:

答案 0 :(得分:17)

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

诀窍在于传递一个C样式数组的参数。当您将1D数组指定为普通函数的正常参数时,其类型将从“数组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编译器(并且,如果内存服务,即使使用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::beginstd::end无法接受。在C ++中,您不能传递数组,而是作为指针或引用。如果它是一个指针,那么它不会携带传递数组的任何信息。

您的替代方案是std::vectorstd::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));