Дизайн класса С++: динамическая типизация, альтернатива аргументу шаблона?

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

Если M можно исправить во время компиляции, это можно сделать с помощью шаблонов:

template <typename num, num M> class Mod_template
{
    private:
        num V;
    public:
        Mod_template(num v=0)
        {
            if (M == 0)
                V = v;
            else
            {
                V = v % M;
                if (V < 0)
                    V += M;
            }
        }
        // ...
};

Mod_template<int, 5> m1(2); // 2 mod 5

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

template <typename num> class Mod
{
    private:
        const num M;
        num V;
    public:
        Mod(num m, num v=0): M(abs(m))
        {
            if (M == 0)
                V = v;
            else
            {
                V = v % M;
                if (V < 0)
                    V += M;
            }
        }
        // ...
};

Mod<int> m2(5, 2); // 2 mod 5
Mod<int> m3(3);    // 0 mod 3

Это работает, но большой вектор значений mod M использует в 2 раза больше места, чем ему нужно.

Я думаю, что основная концептуальная проблема заключается в том, что Моды разных модулей синтаксически относятся к одному и тому же типу, даже если они «должны» быть разными типами. Например, такое заявление, как

m2 = m3;

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

Итак, есть ли способ реализовать какую-то динамическую типизацию, чтобы тип объекта Mod запоминал модуль? Я был бы очень признателен за любую идею, как решить эту проблему.

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

РЕДАКТИРОВАТЬ: насколько я понимаю,

  • шаблоны — это типы, параметризованные классом или литералом.

  • что я хочу: тип, параметризованный константным объектом (const num в данном случае, const Group& или const Group *const для групп и т. д.).

Это возможно?


person EdgarTheWise    schedule 23.06.2014    source источник
comment
Подробнее об удалении текста   -  person Manu343726    schedule 23.06.2014
comment
@Manu343726 Manu343726: Спасибо, это действительно интересно, но я не мог понять, как применить это, чтобы делать то, что я хочу. Не могли бы вы уточнить это?   -  person EdgarTheWise    schedule 23.06.2014
comment
Что, если вы предоставите как класс с членом среды выполнения, так и шаблон с неявным преобразованием из Mod_template<T,M> в Mod<T> и явным преобразованием (которое может вызвать или утвердить или что-то еще) из Mod<T> в Mod_template<T,M>? Я признаю, что определение операторов было бы еще сложнее...   -  person aschepler    schedule 23.06.2014
comment
@aschepler: Спасибо! Одна из проблем заключается в том, что мне нужно знать заранее все M, которые могут быть использованы. Но это может быть осуществимо.   -  person EdgarTheWise    schedule 25.06.2014
comment
Нет, вам не нужно перечислять набор возможных значений M.   -  person aschepler    schedule 26.06.2014


Ответы (1)


Будет трудно сделать это в нулевом пространстве для хранения, если классу нужно знать, каким должно быть M без какой-либо посторонней помощи. Вероятно, лучшее, что вы можете сделать, это сохранить указатель на общий M, что может быть немного лучше в зависимости от размера num. Но это не так хорошо, как бесплатно.

Проектировать будет проще, если M будет передаваться всем функциям, которые в нем нуждаются. Затем вы можете делать такие вещи, как создание пула объектов, которые используют один и тот же M (существует множество простых способов спроектировать это, например, map<num, vector<num> >) и хранить M только один раз для пула. Вызывающему необходимо знать, из какого пула поступил объект Mod, но, вероятно, он и так это знает.

Трудно ответить на этот вопрос полностью изолированно... знание большего количества кода вызова определенно поможет вам получить более точные ответы.

person StilesCrisis    schedule 23.06.2014
comment
Спасибо за этот ответ! Передача M — допустимый метод, но он ухудшит читабельность кода. Контекст: я хотел бы добавить два вектора одинаковой длины. Да, мы могли бы сохранить массив num и привести тип к модулю, добавить, привести обратно к num. Я надеялся, что есть лучший способ. - person EdgarTheWise; 23.06.2014
comment
Почему бы вам просто не оставить их всегда как Mods? Mod в этот момент будет просто обернутым num с дополнительными методами для выполнения арифметики. - person StilesCrisis; 23.06.2014
comment
Когда я занимаюсь арифметикой с огромными векторами/матрицами, двукратная разница в пространстве действительно может учитываться. Кроме того, меня эстетически беспокоит, что проверки типов выполняются вручную: например. при добавлении m1 + m2 мой код должен явно проверять, что они имеют одинаковый модуль. - person EdgarTheWise; 23.06.2014
comment
Двойной разницы нет. Я не уверен, что вы поняли мое предложение. - person StilesCrisis; 23.06.2014
comment
Наверное, нет. Я думал, вы предлагаете хранить все значения в файле std::vector<Mod>. Каждый объект Mod хранит M (одинаковый для всего вектора), а также V. (Объекту Mod_template<num, M> не нужно хранить M, но M нужно жестко закодировать.) - person EdgarTheWise; 23.06.2014
comment
Да, я не это имел в виду. Перечитайте то, что я написал, и сосредоточьтесь на втором абзаце... Я не знаю, как объяснить это более понятно. Сохраните одно значение M, а затем создайте пул всех объектов Mod, которые совместно используют M. Объект Mod больше не будет знать, что такое его M, поэтому вы передаете его всем функциям по мере необходимости. - person StilesCrisis; 23.06.2014