将未知大小的std :: array传递给函数

Adr*_*ian 84 c++ c++11 stdarray

在C++ 11中,我将如何编写一个采用已知类型但未知大小的std ::数组的函数(或方法)?

// made up example
void mulArray(std::array<int, ?>& arr, const int multiplier) {
    for(auto& e : arr) {
        e *= multiplier;
    }
}

// lets imagine these being full of numbers
std::array<int, 17> arr1;
std::array<int, 6>  arr2;
std::array<int, 95> arr3;

mulArray(arr1, 3);
mulArray(arr2, 5);
mulArray(arr3, 2);
Run Code Online (Sandbox Code Playgroud)

在我的搜索过程中,我只找到了使用模板的建议,但这些看起来很混乱(标题中的方法定义),而且我想要完成的内容过多.

是否有一种简单的方法可以实现这一点,就像普通的C风格数组一样?

And*_*owl 74

是否有一种简单的方法可以实现这一点,就像普通的C风格数组一样?

不.你真的不能这样做,除非你把你的函数变成一个函数模板(或者使用另一种容器,就像std::vector问题的评论中所建议的那样):

template<std::size_t SIZE>
void mulArray(std::array<int, SIZE>& arr, const int multiplier) {
    for(auto& e : arr) {
        e *= multiplier;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是一个实例.

  • OP询问是否有其他解决方案,但模板. (7认同)
  • 关于在这里使用模板的美妙部分是你可以使它更通用,因此它适用于任何序列容器,以及标准数组:`template <typename C,typename M> void mulArray(C&arr,M乘数){/*同一身体*/}` (4认同)
  • @Adrian:不幸的是,如果您希望您的函数在任何大小的数组上通用,则没有其他解决方案...... (3认同)
  • 正确:没有其他办法。由于每个具有不同大小的 std::array 都是不同的类型,因此您需要编写一个可以处理不同类型的函数。因此,模板是 std::array 的解决方案。 (3认同)
  • @BenjaminLindley:当然,这是假设他可以将代码放在标题中。 (2认同)

Mar*_*k B 24

大小array类型的一部分,所以你不能做你想要的.有几种选择.

首选是采用一对迭代器:

template <typename Iter>
void mulArray(Iter first, Iter last, const int multiplier) {
    for(; first != last; ++first) {
        *first *= multiplier;
    }
}
Run Code Online (Sandbox Code Playgroud)

或者,使用vector而不是数组,它允许您在运行时而不是作为其类型的一部分存储大小:

void mulArray(std::vector<int>& arr, const int multiplier) {
    for(auto& e : arr) {
        e *= multiplier;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我认为这是最好的解决方案;如果您要解决制作模板的麻烦,请使用迭代器使其完全通用,这样您就可以使用*任何* 容器(数组、列表、向量,甚至是老派的 C 指针等)而没有任何缺点。谢谢你的提示。 (2认同)

sun*_*cho 11

编辑

C++20 暂定包括 std::span

https://en.cppreference.com/w/cpp/container/span

原答案

您想要的是类似于gsl::spanC++ 核心指南中描述的指南支持库中的内容:

https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#SS-views

您可以在此处找到 GSL 的开源头文件实现:

https://github.com/Microsoft/GSL

使用gsl::span,您可以执行以下操作:

// made up example
void mulArray(gsl::span<int>& arr, const int multiplier) {
    for(auto& e : arr) {
        e *= multiplier;
    }
}

// lets imagine these being full of numbers
std::array<int, 17> arr1;
std::array<int, 6>  arr2;
std::array<int, 95> arr3;

mulArray(arr1, 3);
mulArray(arr2, 5);
mulArray(arr3, 2);
Run Code Online (Sandbox Code Playgroud)

问题std::array在于它的大小是其类型的一部分,因此您必须使用模板来实现一个具有std::array任意大小的函数。

gsl::span另一方面,将其大小存储为运行时信息。这允许您使用一个非模板函数来接受任意大小的数组。它还将接受其他连续容器:

std::vector<int> vec = {1, 2, 3, 4};
int carr[] = {5, 6, 7, 8};

mulArray(vec, 6);
mulArray(carr, 7);
Run Code Online (Sandbox Code Playgroud)

很酷吧?


小智 5

我在下面尝试过,它只是为我工作。

#include <iostream>
#include <array>

using namespace std;

// made up example
void mulArray(auto &arr, const int multiplier) 
{
    for(auto& e : arr) 
    {
        e *= multiplier;
    }
}

void dispArray(auto &arr)
{
    for(auto& e : arr) 
    {
        std::cout << e << " ";
    }
    std::cout << endl;
}

int main()
{

    // lets imagine these being full of numbers
    std::array<int, 7> arr1 = {1, 2, 3, 4, 5, 6, 7};
    std::array<int, 6> arr2 = {2, 4, 6, 8, 10, 12};
    std::array<int, 9> arr3 = {1, 1, 1, 1, 1, 1, 1, 1, 1};

    dispArray(arr1);
    dispArray(arr2);
    dispArray(arr3);

    mulArray(arr1, 3);
    mulArray(arr2, 5);
    mulArray(arr3, 2);

    dispArray(arr1);
    dispArray(arr2);
    dispArray(arr3);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

1 2 3 4 5 6 7

2 4 6 8 10 12

1 1 1 1 1 1 1 1 1

3 6 9 12 15 18 21

10 20 30 40 50 60

2 2 2 2 2 2 2 2 2

  • 这不是有效的C ++,而是扩展。这些功能都是模板,即使没有`template`。 (2认同)

Dav*_*uth 5

当然,在 C++11 中有一种简单的方法来编写一个函数,该函数采用已知类型但未知大小的 std::array。

如果我们无法将数组大小传递给函数,那么我们可以传递数组开始位置的内存地址以及数组结束位置的第二个地址。稍后,在函数内部,我们可以使用这2个内存地址来计算数组的大小!

#include <iostream>
#include <array>

// The function that can take a std::array of any size!
void mulArray(int* piStart, int* piLast, int multiplier){

     // Calculate the size of the array (how many values it holds)
     unsigned int uiArraySize = piLast - piStart;

     // print each value held in the array
     for (unsigned int uiCount = 0; uiCount < uiArraySize; uiCount++)     
          std::cout << *(piStart + uiCount) * multiplier << std::endl;
}

int main(){   

     // initialize an array that can can hold 5 values
     std::array<int, 5> iValues;

     iValues[0] = 5;
     iValues[1] = 10;
     iValues[2] = 1;
     iValues[3] = 2;
     iValues[4] = 4;

     // Provide a pointer to both the beginning and end addresses of 
     // the array.
     mulArray(iValues.begin(), iValues.end(), 2);

     return 0;
}
Run Code Online (Sandbox Code Playgroud)

控制台输出: 10, 20, 2, 4, 8