将未知大小的std ::数组传递给一个函数

在C ++ 11中,我将如何去编写一个函数(或方法),它需要一个已知types的未知大小的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); 

在我的search过程中,我只find了使用模板的build议,但是这些看起来很乱(头文件中的方法定义),而我试图完成的东西太多了。

有一个简单的方法来做这个工作,就像一个简单的C风格的数组?

有一个简单的方法来做这个工作,就像一个简单的C风格的数组?

不,你真的不能这样做,除非你使你的函数成为一个函数模板 (或者使用另一种容器,比如std::vector ,如问题的注释中所build议的那样):

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

这是一个生动的例子

array的大小是types的一部分 ,所以你不能做你想要的。 有几个select。

首选的是采取一对迭代器:

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

或者,使用vector而不是array,它允许您在运行时存储大小而不是其types的一部分:

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

这可以完成,但需要几个步骤干净地做。 首先,编写一个代表一系列连续值的template class 。 然后转发一个template版本,该版本知道该array对于使用此连续范围的Impl版本有多大。

最后,实施contig_range版本。 注意for( int& x: range )对于contig_range ,因为我实现了begin()end() ,指针是迭代器。

 template<typename T> struct contig_range { T* _begin, _end; contig_range( T* b, T* e ):_begin(b), _end(e) {} T const* begin() const { return _begin; } T const* end() const { return _end; } T* begin() { return _begin; } T* end() { return _end; } contig_range( contig_range const& ) = default; contig_range( contig_range && ) = default; contig_range():_begin(nullptr), _end(nullptr) {} // maybe block `operator=`? contig_range follows reference semantics // and there really isn't a run time safe `operator=` for reference semantics on // a range when the RHS is of unknown width... // I guess I could make it follow pointer semantics and rebase? Dunno // this being tricky, I am tempted to =delete operator= template<typename T, std::size_t N> contig_range( std::array<T, N>& arr ): _begin(&*std::begin(arr)), _end(&*std::end(arr)) {} template<typename T, std::size_t N> contig_range( T(&arr)[N] ): _begin(&*std::begin(arr)), _end(&*std::end(arr)) {} template<typename T, typename A> contig_range( std::vector<T, A>& arr ): _begin(&*std::begin(arr)), _end(&*std::end(arr)) {} }; void mulArrayImpl( contig_range<int> arr, const int multiplier ); template<std::size_t N> void mulArray( std::array<int, N>& arr, const int multiplier ) { mulArrayImpl( contig_range<int>(arr), multiplier ); } 

(没有testing,但devise应该工作)。

然后,在你的.cpp文件中:

 void mulArrayImpl(contig_range<int> rng, const int multiplier) { for(auto& e : rng) { e *= multiplier; } } 

这有一个缺点,那就是遍历数组内容的代码并不知道(在编译时)数组有多大,这可能会花费优化。 它的优点是实现不必在头部。

要小心显式构造一个contig_range ,就好像你传递了一个set它会假设set数据是连续的,这是假的,并且在整个地方做了未定义的行为。 只有两个std容器,这是保证工作是vectorarray (和C风格的数组,就像它发生!)。 deque尽pipe随机访问是不连续的(危险的是,它是连续的小块!), list甚至没有closures,并且联合(有序和无序)容器是同样不连续的。

所以我实现了三个构造函数,其中std::arraystd::vector和C-style数组基本上覆盖了基础。

实现[]也很容易,在for()[]之间for()这是你想要一个array大部分,不是吗?

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

  #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; } 

输出:

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