Доступ к элементам массива базового типа (идиома типа Int-to-Type) - PullRequest
0 голосов
/ 22 января 2019

Пытаясь реализовать идиому типа Int-to-Type, я столкнулся с проблемой внутри моего унаследованного класса, которую не могу решить даже после того, как попробую несколько аналогичных решений из других постов здесь.Я пытаюсь реализовать простой алгоритм сортировки массива в унаследованном классе.Для начала я устанавливаю перечисление int-to-type и структуру:

enum class Technique : int
{
    NOOP,
    INSERTION_SORT,
    QUICK_SORT
};
template <Technique I>
struct AutoTechnique
{
    enum { value = I };
};

Далее я определяю свой класс Array, наследующий от std :: array с некоторыми инструментами для обработки различных методов сортировки на основе размераколлекция:

template <typename T, unsigned N>
class Array : public std::array<T, N>
{
    static const Technique technique = (N == 0 || N == 1) ? Technique::NOOP :
        (N < 50) ? Technique::INSERTION_SORT : Technique::QUICK_SORT;

    void sort(AutoTechnique<Technique::NOOP>)
    {
        std::cout << "NOOP\n";
    }
    void sort(AutoTechnique<Technique::INSERTION_SORT>)
    {
        int i, j;
        T temp;
        for (i = 1; i < N; i++)
        {
            j = i;
            while (j > 0 && this[j - 1] > this[j])
            {
                temp = this[j]; // Wants to assign Array<T,N> to temp, rather than value at index.
                this[j] = this[j - 1];
                this[j - 1] = temp;
                j--;
            }
        }
    }
    void sort(AutoTechnique<Technique::QUICK_SORT>)
    {
        std::cout << "QUICK_SORT\n";
    }
public:
    void Sort()
    {
        sort(AutoTechnique<technique>());
    }

};

Проблема в строке с комментарием, компилятор говорит мне "= cannot convert from Array<int,49> to T" (int, 49 - тестовый пример).

Лучший ответ, который я смог найти, был близок к этому, это предложение, что мне нужно разыменовать this (* this) и получить доступ к значению с помощью ->, но код двумя строками выше, кажется, работает, где яне делать этого, и несколько вариантов попытки разыменования объекта не работали.

Кажется, что основная проблема заключается в попытке присвоить значение в этом [j] T temp.Я попытался привести (T)this[j], и я получаю сообщение об ошибке type cast cannot convert...

Как сохранить значение в индексе массива this во временной переменной, которая соответствует типу, предоставленному массиву?

Ответы [ 2 ]

0 голосов
/ 22 января 2019

Обновлен код из ответа, предоставленного @ NathanOliver

void sort(AutoTechnique<Technique::INSERTION_SORT>)
{
    int i, j;
    T temp;
    for (i = 1; i < N; i++)
    {
        j = i;
        while (j > 0 && (*this)[j - 1] > (*this)[j])
        {
            temp = (*this)[j];
            (*this)[j] = (*this)[j - 1];
            (*this)[j - 1] = temp;
            j--;
        }
    }
}
0 голосов
/ 22 января 2019

Позвольте мне использовать пример ...

class foo {};

int main() {
    foo* a;
    a+5;       // fine ? 
    a[3];      // fine ? 
    foo b;
    b+5;       // error: no operator found
    b[3];      // error: no operator found
}

Существуют определенные операторы для указателей (пример не завершен, смысл лишь в том, чтобы продемонстрировать, что они не являются операторами для объектов).Они работают для указателей любого типа.Вы потребляете операции над указателями с операциями над экземплярами.Сравнение указателей - это не то же самое, что сравнение объектов.

Более того, когда a является указателем, тогда a[b] это просто *(a+b).Следовательно, в вашем коде это работает, но на самом деле это не так.Вы обрабатываете this, как если бы это был указатель на массив объектов, а затем разыменовываете его в тех местах памяти, где нет Array объектов (у вас есть только один, а не их массив).На самом деле вы обращаетесь за пределы, и ваш код имеет неопределенное поведение.

Сообщение об ошибке фактически объясняет, что не так:

= не может преобразовать из массива в T

, потому что здесь

temp = this[j];

temp - это, конечно, T, тогда как this[j] == *(this + j), т.е. вы увеличиваете указатель this на jsizeof(Array<int,49>) (вот что происходит, когда вы добавляете целое число к указателю определенного типа) и затем вы разыменовываете указатель, чтобы получить Array<int,49>.Для этих типов нет оператора присваивания, следовательно, ошибка.

Более того, в этой ячейке памяти нет Array<int,49>.На самом деле вам повезло получить ошибку компилятора, обычно неопределенное поведение более скрыто, скрывается за невинно выглядящими предупреждениями или, что еще хуже, без предупреждений и кажется работающим, когда его на самом деле нет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...