Можно ли использовать `std :: copy` для копирования значений из массива переменного размера в контейнер? - PullRequest
3 голосов
/ 26 апреля 2019

Ниже приведена реализация MergeSort.Моя проблема заключается в том, что компилятор жалуется, что std::begin нельзя применить к массиву переменного размера temp для дальнейшего использования std:copy.

Я использую C ++ 17 и gcc 8.3 .

template<typename Container, typename Iterator>
void Search::MergeSort(Container &array, Iterator begin, Iterator end)
{
    auto const len = end - begin;
    if (len > 1)
    {
        auto mid = begin + len / 2;
        MergeSort(array, begin, mid); 
        MergeSort(array, mid, end); 

        typename Container::value_type temp[len];

        int p = 0;
        for (auto i = begin, j = mid; i < mid; ++i)
        {
            auto curr = *i;
            while (j < end && *j < curr) temp[p++] = *j++;
            temp[p++] = curr;
        }

        auto temp_begin = std::begin(temp); // ! problem: unable to compile this line
        copy(temp_begin, temp_begin + p, begin);
    }

К сообщениям об ошибках относятся:

template argument deduction/substitution failed:
note: mismatched types 'std::initializer_list<_Tp>' and 'std::vector<int>::value_type*' {aka 'int*'}
      variable-sized array type 'std::vector<int>::value_type [len]' {aka 'int [len]'} is not a valid template argument

enter image description here

Ответы [ 2 ]

7 голосов
/ 26 апреля 2019

Можно ли использовать std::copy для копирования значений из с переменным размером массив в контейнер?

Чтобы ответить на ваш вопрос. Да , точно так же, как в @ Максим Егорушкин , ответ можно сделать.

Однако, пожалуйста, не используйте массив переменной длины с, потому что полагаться на что-то , не являющееся частью стандарта C ++, - плохая идея.

Во-вторых, C ++ предоставляет лучшие варианты, такие как std::vector с или std::array с; поэтому просто используйте их.

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

#include <vector>

using value_type = typename Container::value_type;

/* or by iterator_traits
 * using value_type = typename std::iterator_traits<Iterator>::value_type;
 */
std::vector<value_type> temp(len);

Если бы len была бы переменной, известной во время компиляции, вы могли бы также использовать std::array.

4 голосов
/ 26 апреля 2019

Проблема в std::begin/end не определены для массивов переменного размера.

Массивы переменного размера - это функция C99 и нестандартное расширение C ++.Однако иногда они являются лучшим выбором с точки зрения производительности.

Однако можно получить итераторы для массива переменного размера с использованием простой арифметики указателей:

std::copy(temp + 0, temp + p, begin);

Если ваш компилятор C ++ не поддерживает это расширение на некоторых платформах, таких как WindowsLinux и, вероятно, большинство Unix-подобных платформ предоставляют вместо этого функцию alloca.Помните, что это просто функция выделения памяти (аналогично malloc), поэтому она не вызывает конструкторы и не инициализирует выделенную память.

...