알 수없는 크기의 std :: array를 함수에 전달
C ++ 11에서 std :: array의 알려진 유형이지만 크기를 알 수없는 함수 (또는 메서드)를 작성하려면 어떻게해야합니까?
// 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);
검색하는 동안 템플릿 사용에 대한 제안 만 찾았지만, 그것들은 지저분하고 (헤더의 메서드 정의) 내가 달성하려는 작업에 대해 과도하게 보입니다.
일반 C 스타일 배열에서와 같이이 작업을 수행하는 간단한 방법이 있습니까?
일반 C 스타일 배열에서와 같이이 작업을 수행하는 간단한 방법이 있습니까?
아니요. 함수를 함수 템플릿으로 만들지 않으면 실제로 그렇게 할 수 없습니다 (또는 std::vector
질문에 대한 주석에서 제안한대로 , 같은 다른 종류의 컨테이너를 사용 ).
template<std::size_t SIZE>
void mulArray(std::array<int, SIZE>& arr, const int multiplier) {
for(auto& e : arr) {
e *= multiplier;
}
}
다음은 실제 예 입니다.
의 크기는 array
이다 유형의 일부 당신이 원하는 아주 일을 할 수 없도록. 몇 가지 대안이 있습니다.
이터레이터 쌍을 사용하는 것이 좋습니다.
template <typename Iter>
void mulArray(Iter first, Iter last, const int multiplier) {
for(; first != last; ++first) {
*first *= multiplier;
}
}
또는 vector
배열 대신 사용 하여 유형의 일부가 아닌 런타임에 크기를 저장할 수 있습니다.
void mulArray(std::vector<int>& arr, const int multiplier) {
for(auto& e : arr) {
e *= multiplier;
}
}
나는 아래에서 시도했고 그것은 나를 위해 일했습니다.
#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;
}
출력 :
12 34 5 6 7
24 6 8 10 12
111111 1111 1
3 6 9 12 15 18 21
10 20 30 40 50 60
2222222222
물론 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;
}
콘솔 출력 : 10, 20, 2, 4, 8
편집하다
C ++ 20은 잠정적으로 다음을 포함합니다. std::span
https://en.cppreference.com/w/cpp/container/span
Original Answer
What you want is something like gsl::span
, which is available in the Guideline Support Library described in the C++ Core Guidelines:
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#SS-views
You can find an open-source header-only implementation of the GSL here:
https://github.com/Microsoft/GSL
With gsl::span
, you can do this:
// 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);
The problem with std::array
is that its size is part of its type, so you'd have to use a template in order to implement a function that takes an std::array
of arbitrary size.
gsl::span
on the other hand stores its size as run-time information. This allows you to use one non-template function to accept an array of arbitrary size. It will also accept other contiguous containers:
std::vector<int> vec = {1, 2, 3, 4};
int carr[] = {5, 6, 7, 8};
mulArray(vec, 6);
mulArray(carr, 7);
Pretty cool, huh?
This can be done, but it takes a few steps to do cleanly. First, write a template class
that represents a range of contiguous values. Then forward a template
version that knows how big the array
is to the Impl
version that takes this contiguous range.
Finally, implement the contig_range
version. Note that for( int& x: range )
works for contig_range
, because I implemented begin()
and end()
and pointers are iterators.
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 );
}
(not tested, but design should work).
Then, in your .cpp
file:
void mulArrayImpl(contig_range<int> rng, const int multiplier) {
for(auto& e : rng) {
e *= multiplier;
}
}
This has the downside that the code that loops over the contents of the array doesn't know (at compile time) how big the array is, which could cost optimization. It has the advantage that the implementation doesn't have to be in the header.
Be careful about explicitly constructing a contig_range
, as if you pass it a set
it will assume that the set
data is contiguous, which is false, and do undefined behavior all over the place. The only two std
containers that this is guaranteed to work on are vector
and array
(and C-style arrays, as it happens!). deque
despite being random access isn't contiguous (dangerously, it is contiguous in small chunks!), list
is not even close, and the associative (ordered and unordered) containers are equally non-contiguous.
So the three constructors I implemented where std::array
, std::vector
and C-style arrays, which basically covers the bases.
Implementing []
is easy as well, and between for()
and []
that is most of what you want an array
for, isn't it?
참고URL : https://stackoverflow.com/questions/17156282/passing-a-stdarray-of-unknown-size-to-a-function
'program story' 카테고리의 다른 글
JavaGit, JGit 및 EGit 선택시 혼란 (0) | 2020.10.08 |
---|---|
언제 그리고 왜 수업을 봉인 하시겠습니까? (0) | 2020.10.08 |
Windows 아래 Git : MSYS 또는 Cygwin? (0) | 2020.10.08 |
.NET에서 이중 체크 잠금에서 휘발성 수정 자 필요 (0) | 2020.10.08 |
직접 실행 창에서 데이터 테이블 또는 데이터보기의 내용을 쉽게 볼 수있는 방법 (0) | 2020.10.07 |