为什么我不能将C风格数组复制到std :: array中?

21

我有这段代码:

 std::array<int,16> copyarray(int input[16])
{
    std::array<int, 16> result;
    std::copy(std::begin(input), std::end(input), std::begin(result));
    return result;
}

当我尝试编译这段代码时,我会遇到以下错误:

'std::begin': no matching overloaded function found 

还有一个类似的错误是针对std::end的。

问题是什么,我该如何解决?


2
数组参数的大小不是这样工作的,它等于 int *input - Slava
@Slava 怎么修复它? - mans
9
不要使用C风格数组。它们无法知道自己的大小,并在用作函数参数时转换为指针。没有任何std :: begin重载接受指针类型。 - Ron
2
@Ron 避免使用数组可能是问题的意图 - 可能代码中有一个无法更改的数组吗? - Aconcagua
1
您还可以使用 std::memcpy(result.data(), input, sizeof(input)); 在它们之间进行复制。将两个数组的大小定义为相同的 constexpr size_t 值可能是一个好习惯。如果在多个地方重新输入 16,并且它们不同步,那么就会发生缓冲区溢出或下溢。 - Davislor
显示剩余2条评论
3个回答

41
在参数声明中,int input[16]int* input是相同的。当您传递数组参数时,数组将退化为指针,这两个声明都意味着数组大小的信息会丢失。同时,std::beginstd::end不能与指针一起使用。
您可以更改为通过引用传递参数,这样就可以保留数组的大小信息。
std::array<int,16> copyarray(int (&input)[16])

请注意,现在您只能传递大小为16的确切数组到该函数中。


12
或者使用裸指针(inputinput+16)来运行算法。当然并不推荐,但有时候别无选择。 - 463035818_is_not_a_number
8
你甚至可以添加缺少的 const - Jarod42

34

所有重要的已经说过了,你只需要让这个函数更加灵活:

template <typename T, size_t N>
std::array<T, N> copyarray(T const (&input)[N])
{
    std::array<T, N> result;
    std::copy(std::begin(input), std::end(input), std::begin(result));
    return result;
}

(晚些时候)编辑:上述方法存在一个缺点:您需要在分配时复制返回的数组,因为它不包含任何真正可移动的数据(原始数组也是如此)。您可以通过直接复制到目标数组来避免这种缺点:

template <typename T, size_t N>
void copyarray(std::array<T, N>& target, T const (&source)[N])
{
    std::copy(std::begin(source), std::end(source), std::begin(target));
}

这个函数模拟了赋值操作target = source; 当然,如果你喜欢,可以交换参数,使输出参数位于最后。

用法(如下):

int source[7] = { };
std::array<int, sizeof(source)/sizeof(*source)> target;
copyarray(target, source);

模板 <typename T,size_t N> 是从<array>到std :: array定义的。 - Ulrich Von Rekkenin
@UlrichVonRekkenin,你想表达什么?模板参数必须相同,否则你怎么能够对数组进行通用引用呢?这种模式在许多其他地方也会出现——例如,你是否看过针对数组的std::begin/end变体? - Aconcagua

1
正如先前所述,问题在于当数组传递到函数时会衰减为指针,这意味着大小不会被保留。
但是,如果您知道数组中有16个元素,您可以这样做:
array<int,16> copyarray(const int input[]) {
    array<int, 16> result;
    copy_n(input, size(result), begin(result));
    return result;
}    

如果你不限制在16上,你可以使用template<unsigned N> array<int,N> copyarray(const int (&input)[N]) { ... }来保留大小。编辑 - Aconcagua也可以这样参数化,但是使用class T代替int - John P
@JohnP 是的,只是把这个作为另一种选择呈现出来。 - Jonathan Mee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接