Передача std :: array неизвестного размера функции

В C ++ 11, как бы я начал писать функцию (или метод), которая принимает std :: массив известного типа, но неизвестного размера?

// made up example void mulArray(std::array& arr, const int multiplier) { for(auto& e : arr) { e *= multiplier; } } // lets imagine these being full of numbers std::array arr1; std::array arr2; std::array arr3; mulArray(arr1, 3); mulArray(arr2, 5); mulArray(arr3, 2); 

Во время моего поиска я только нашел предложения по использованию шаблонов, но они кажутся беспорядочными (определения методов в заголовке) и чрезмерными для того, что я пытаюсь выполнить.

Есть ли простой способ сделать эту работу, как и обычные C-образные массивы?

    Есть ли простой способ сделать эту работу, как и обычные C-образные массивы?

    Нет. Вы действительно не можете этого сделать, если вы не сделаете свою функцию шаблоном функции (или используйте другой тип контейнера, например std::vector , как это предлагается в комментариях к вопросу):

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

    Вот живой пример .

    Размер array является частью типа , поэтому вы не можете делать то, что хотите. Есть несколько альтернатив.

    Предпочтительным было бы взять пару iteratorов:

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

    В качестве альтернативы используйте vector вместо массива, который позволяет хранить размер во время выполнения, а не как часть его типа:

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

    Я попробовал ниже, и это просто сработало для меня.

     #include  #include  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 arr1 = {1, 2, 3, 4, 5, 6, 7}; std::array arr2 = {2, 4, 6, 8, 10, 12}; std::array 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

    Это можно сделать, но для этого нужно сделать несколько шагов. Сначала напишите template class который представляет диапазон смежных значений. Затем template версию template которая знает, насколько большой array для версии Impl которая принимает этот непрерывный диапазон.

    Наконец, выполните версию contig_range . Обратите внимание, что for( int& x: range ) работает для contig_range , потому что я реализовал begin() и end() а указатели – iteratorы.

     template 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 contig_range( std::array& arr ): _begin(&*std::begin(arr)), _end(&*std::end(arr)) {} template contig_range( T(&arr)[N] ): _begin(&*std::begin(arr)), _end(&*std::end(arr)) {} template contig_range( std::vector& arr ): _begin(&*std::begin(arr)), _end(&*std::end(arr)) {} }; void mulArrayImpl( contig_range arr, const int multiplier ); template void mulArray( std::array& arr, const int multiplier ) { mulArrayImpl( contig_range(arr), multiplier ); } 

    (не тестировалось, но дизайн должен работать).

    Затем в файле .cpp :

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

    Это имеет недостаток, что код, который перебирает содержимое массива, не знает (во время компиляции), насколько велик массив, что может стоить оптимизации. Это имеет то преимущество, что реализация не обязательно должна быть в заголовке.

    Будьте осторожны с явным конструированием contig_range , как если бы вы contig_range ему set он будет считать, что set данные смежны, что является ложным, и делают неопределенное поведение повсюду. Единственные два std контейнера, над которыми это гарантировано работает, – это vector и array (и массивы C-стиля, как это бывает!). deque несмотря на случайный доступ, не соприкасается (опасно, он смежн в небольших кусках!), list даже не близок, а ассоциативные (упорядоченные и неупорядоченные) контейнеры одинаково непересекаются.

    Итак, три конструктора, которые я реализовал, где std::array , std::vector и C-style массивы, которые в основном покрывают базы.

    Реализация [] проста, и между for() и [] что больше всего для вас требуется array , не так ли?

    Абсолютно, в C ++ 11 есть простой способ написать функцию, которая принимает std :: массив известного типа, но неизвестного размера.

    Если мы не можем передать размер массива функции, вместо этого мы можем передать адрес памяти, где начинается массив, со вторым адресом, где заканчивается массив. Позже, внутри функции, мы можем использовать эти 2 адреса памяти для вычисления размера массива!

     #include  #include  // 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 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

    То, что вы хотите, – это что-то вроде gsl::span , которое доступно в библиотеке поддержки руководств, описанной в Основных принципах C ++:

    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& arr, const int multiplier) { for(auto& e : arr) { e *= multiplier; } } // lets imagine these being full of numbers std::array arr1; std::array arr2; std::array arr3; mulArray(arr1, 3); mulArray(arr2, 5); mulArray(arr3, 2); 

    Проблема с std::array заключается в том, что его размер является частью его типа, поэтому вам нужно будет использовать шаблон для реализации функции, которая принимает std::array произвольного размера.

    gsl::span с другой стороны, сохраняет свой размер как информацию о времени выполнения. Это позволяет использовать одну функцию без шаблона для принятия массива произвольного размера. Он также примет другие смежные контейнеры:

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

    Довольно круто, да?

    Interesting Posts

    Суперclass «javax.servlet.http.HttpServlet» не найден на пути сборки Java

    Копирование файла в Windows 8 дает «недостаточно памяти» даже при большом объеме памяти и дискового пространства

    Устранение неполадок использования центрального процессора с помощью процесса «Система»

    Что делать с нулевыми значениями при моделировании и нормализации?

    Как ограничить приложение Android конкретным устройством?

    Обновление вложенных массивов в mongodb

    Log4J2 – назначение имени файла файла appender во время выполнения

    Сплавленные многократные добавления и режимы округления по умолчанию

    Включить / отключить сетевой адаптер с помощью сочетания клавиш

    Какие аргументы передаются в AsyncTask ?

    Передайте переменную javascript в качестве параметра в @ url.Action ()

    Как реализовать Elevation Material-Design для Pre-lollipop

    Как разрешить выход ASMX-файла JSON

    Как перебирать элементы, возвращаемые функцией с помощью ng-repeat?

    использование курсора в android

    Давайте будем гением компьютера.