Пакет параметров шаблона Variadic для приема только беззнаковых целых чисел или size_t в качестве своего типа

Я пытаюсь использовать набор классов шаблонов с переменным параметром. У меня впереди несколько вариантов, из которых я мог бы выбрать. До того, как какой-либо из моих шаблонов будет объявлен или определен, у меня в настоящее время есть эти прототипы: я знаком с шаблонами, но у меня не было большого опыта работы с вариативными типами при работе с шаблонами, поэтому синтаксис иногда меня немного сбивает с толку. Поскольку все они являются пустыми оболочками, они в настоящее время компилируются.

template<typename ClassType, typename... Args>  class MatrixReference;
template<typename ClassType, typename... Args>  class MatrixStorage;
template<typename ClassType, typename... Args>  class MatrixAllocation;

У меня есть пользовательский класс, который будет использовать эти классы в зависимости от целей использования; в настоящее время это пустая оболочка, пока я не получу другие классы, определенные правильно с соответствующим поведением:

template<typename ClassType, typename... Args>
class Matrix {      
};

Остальная часть класса из прототипов, показанных выше, будет унаследована от базового класса, так что указанный выше пользовательский класс будет иметь их контейнер, такой, что контейнер будет: std::vector<std::unique_ptr<MatrixBase>> или std::vector<shared_ptr<MatrixBase>>, а вектор будет содержать только 1 каждого типа из перечисленные прототипы. Например, вектор [0] будет содержать MatrixStorage, вектор [1] будет содержать MatrixReference, а вектор [2] будет содержать MatrixAllocation. У каждого из этих классов разные обязанности, как следует из их названия. Класс хранения будет содержать необработанную копию стека элементов. Ссылочный класс будет использоваться для ссылки на эти копии. Класс распределения будет использоваться при объявлении элементов в куче. Базовый класс выглядит так:

template <typename ClassType = void>
class MatrixBase {
protected:
    MatrixBase(){}
    virtual ~MatrixBase(){}
}; // Matrix

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

Теперь об объявлении моих шаблонов классов: мне действительно нужно использовать здесь только один из них, поскольку все они следуют одному шаблону, но я все равно покажу все 3, поскольку в настоящее время они являются пустыми оболочками.

// Stores All Of The Contents Of The Matrix
template<typename ClassType, typename... Args>
class MatrixStorage : public MatrixBase<ClassType> {
}; // MatrixStorage    

// Used To Reference The Storage Class Of The Matrix
template<typename ClassType, typename... Args>
class MatrixReference : public MatrixBase<ClassType> {
}; // MatrixReference

// Used Only When User Wants To Create A Matrix On The Heap
template<typename ClassType, typename... Args>
class MatrixAllocation : public MatrixBase<ClassType> {
}; // MatrixAllocation

Подход к проектированию, который я ищу, заключается в том, что когда этот класс используется, он следует шаблону, где первый тип всегда является типом данных, которые матрица будет хранить, либо это будет int, float или какой-либо другой определяемый пользователем тип; следующий параметр - это то место, где используется переменный параметр, так что, если создается экземпляр шаблона как такового:

Matrix<float,2,2> mat2x2; // Default constructor making it empty

Это сгенерирует матрицу поплавков размером 2x2.

Matrix<int,3,3,3> mat3x3x3; 

Это сгенерирует объемную матрицу целых чисел 3x3x3

Таким образом, часть вариативного шаблона всегда будет + целых чисел, а минимальное требование будет Matrix<type, 1>, где это будет в некотором смысле скалярная или одноэлементная матрица или матрица 1x1.

Здесь мне предлагается несколько вариантов. Я мог бы использовать следующее

  • size_t ... N
  • беззнаковый ... D
  • typename ... Args

В настоящий момент, как вы можете видеть, он объявлен с последним из вариантов. Итак, теперь возникает главный вопрос:

Если бы я решил использовать Parameter Pack, где у меня есть вспомогательный класс как таковой:

template <typename ClassType,typename... Dimensions>
class DimensionPack {
public: 
    typename std::tuple<ClassType, std::tuple<Dimensions...> >::type Dim;
    const unsigned int numarguments = sizeof...(Dimensions);
};

Вопрос становится; есть ли известный способ сделать параметр Variadic одного и того же типа, а именно size_t или unsigned int? Если да, то пример будет оценен или ссылка на ссылку тоже поможет; Я искал и не нашел ничего полезного, достаточно похожего, чтобы помочь мне в этом.

Если нет, я не возражаю против использования size_t или unsigned int, но я предпочитал иметь возможность использовать вспомогательный шаблон для упаковки и распаковки вариативных параметров таким образом, что мне не нужно реализовывать это в каждом и каждый класс.

У меня также есть 2 других производных класса, которые здесь не показаны, но один будет использоваться для записи их на экран, а другой будет использоваться для чтения и синтаксического анализа из файла и записи в файл.

Также в качестве примечания: для чрезвычайно больших наборов данных или матриц чрезвычайно большого размера: у меня также есть этот вспомогательный класс, который можно использовать для них:

template<typename ClassType, std::size_t bufferSize>
class MatrixBuffer {
    static std::vector<ClassType> matrixBuffer = std::vector<ClassType>().reserve( bufferSize );
};

Изменить

Я забыл добавить это к исходному вопросу, но сейчас добавляю его для большей ясности. Мне действительно нужно протестировать значение каждого вариативного параметра, чтобы увидеть, является ли оно нечетным или четным, и их результаты будут сохранены в векторе с размером количества параметров, хранящих 0 для четных или 1 для нечетных. Это одна из причин, по которой я склонялся к использованию пакета параметров, потому что я мог просто передать его вспомогательной функции, которая вернула бы обратно необходимый вектор.


person Francis Cugler    schedule 02.02.2017    source источник
comment
Есть ли причина, по которой вы не можете просто использовать template<typename ClassType, std::size_t... Args>?   -  person Alex Zywicki    schedule 02.02.2017
comment
@AlexZywicki Я тоже об этом думал, но не был уверен, упростит ли вам вспомогательный класс для извлечения и расширения в std :: tuple.   -  person Francis Cugler    schedule 02.02.2017
comment
@AlexZywicki Ой; Чуть не забыл, но мне нужно проверить, четно или нечетно каждое измерение матрицы. Поэтому вместо того, чтобы просто std::size_t... сохранять их в пакете параметров, необходимо также создать вектор размера этого пакета и заполнить его 0 для четных или 1 для нечетных. Я могу продолжить и добавить ясность к своему вопросу.   -  person Francis Cugler    schedule 02.02.2017
comment
Итак, ответ таков: нет веских причин не использовать size_t...Args. Вы идете по ложному пути.   -  person Yakk - Adam Nevraumont    schedule 02.02.2017
comment
@Yakk Нет; Я рассматривал все варианты и в конце концов использовал size_t..., но что касается моего вспомогательного класса, вместо сохранения в кортеж; В итоге я инициализировал std::vector<> значениями пакета параметров.   -  person Francis Cugler    schedule 03.02.2017
comment
@FrancisCugler Динамическое выделение для хранения констант времени компиляции кажется плохой идеей, но не мои обезьяны, не мой цирк.   -  person Yakk - Adam Nevraumont    schedule 03.02.2017


Ответы (2)


std::size_t... Args и typename... Args не одно и то же. Первый ожидал бы целые числа вроде

Matrix<float,2,2> mat2x2;

в то время как второй будет ожидать вместо этого типов.
Конечно, вы можете использовать std :: integration_constant, но это было бы более подробным:

template <std::size_t N>
using size = std::integral_constant<std::size_t, N>;

Matrix<float,size<2>,size<2>> mat2x2;

С другой стороны, вы можете использовать std :: index_sequence:

template<typename ClassType, std::size_t... Dims>
class Matrix {
    using Dimensions = std::index_sequence<Dims...>;
};
person O'Neil    schedule 02.02.2017
comment
Да, я понимаю это; но я склоняюсь к использованию вспомогательного класса шаблона только для пакета параметров, чтобы сохранить содержимое в std::tuple, который поможет упаковать и распаковать список параметров. Мне также нужно проверить эти параметры, чтобы увидеть, находятся ли они в диапазоне x ›0, и проверить, четные они или нечетные, и сохранить эти результаты в контейнер. Затем я смогу передать это моей вспомогательной функции ... - person Francis Cugler; 02.02.2017
comment
Или я смотрю это ... где я мог бы использовать ‹std :: size_t ...› и все же сохранить это в std :: tuple в тех же вспомогательных классах и функциях. - person Francis Cugler; 02.02.2017
comment
@FrancisCugler А в чем проблема с распаковкой std::index_sequence? - person O'Neil; 02.02.2017
comment
не был знаком с index_sequence - person Francis Cugler; 02.02.2017
comment
Я не хочу, чтобы экземпляр выглядел так: Matrix<float, <2>, <3>> и т. Д. Я бы предпочел просто Matrix<type, value, value, value> - person Francis Cugler; 02.02.2017
comment
@FrancisCugler Тогда у вас нет выбора, используя _1 _ / _ 2_. - person O'Neil; 02.02.2017
comment
Тогда я не смогу сохранить их в std :: tuple - person Francis Cugler; 02.02.2017
comment
@FrancisCugler Нет, кортеж ожидает типы. std::index_sequence это то, что вам нужно. - person O'Neil; 02.02.2017
comment
Ох, ладно; Мне нужно будет изучить документацию std :: index_sequence. - person Francis Cugler; 02.02.2017

Используя static_assert, можно проверить во время компиляции:

template <typename ClassType,typename... Dimensions>
class DimensionPack {
        public:
            DimensionPack(const Dimensions&... args){
                checkType<Dimensions...>(args...);
            }
            ~DimensionPack(){}
        private:
            template<typename T> void checkType(const T& t) {
                static_assert(std::integral_constant<bool, std::is_same<T, size_t>::value>(), "T is not of type size_t");
            }
            template<typename T, typename... V> void checkType(const T& t, const V&... v) {
                static_assert(std::integral_constant<bool, std::is_same<T, size_t>::value>(), "T is not of type size_t");
                checkType<V...>(v...);
            }
    };
person Clonk    schedule 31.08.2017