Преобразовать массив int в шаблон с переменным числом аргументов

Скажем, у меня есть массив int, как int arr[N] и скажи arr[i] из крошечного домена (например, 1-10). Скажем, у меня также есть шаблонный класс с общим интерфейсом (абстрактный класс)

template <int... A>
class FooImpl : public Foo
{
}

Вопрос в том, как мне реализовать функцию:

Foo* getFoo(int arr[N]);

а может лучше:

Foo* getFoo(int* pint, int size);

который бы вернулся FooImpl с аргументами шаблона, соответствующими моему массиву? Например для arr = {4,2,6,1} я бы получил FooImpl<4,2,6,1>

4

Решение

Я нашел ответ на свой вопрос. Хитрость заключается в том, чтобы использовать шаблоны структуры variadic вместо шаблонов функции variadic, которые я изначально пробовал. Я использую структуру _getFoo_impl с функцией func, которая создает элемент за элементом.

Давайте предположим, что элементы находятся в диапазоне [1-5] и размер <= 4, а затем код выглядит следующим образом:

class Foo
{
};

template <int...A>
class FooImpl : Foo {
};

template<int...As>
struct _getFoo_impl
{
static Foo* func(int *arr, int sz)
{
if (sz == 0)
return new FooImpl<As...>;

switch (*arr)
{
case 1: return _getFoo_impl<As..., 1>::func(arr + 1, sz - 1);
case 2: return _getFoo_impl<As..., 2>::func(arr + 1, sz - 1);
case 3: return _getFoo_impl<As..., 3>::func(arr + 1, sz - 1);
case 4: return _getFoo_impl<As..., 4>::func(arr + 1, sz - 1);
case 5: return _getFoo_impl<As..., 5>::func(arr + 1, sz - 1);
default: throw "element out of range";
}
}
};

template<int A1, int A2, int A3, int A4, int A5>
struct _getFoo_impl<A1, A2, A3, A4, A5>
{
static Foo* func(int*, int sz) {
std::terminate();
}
};

Foo* getFoo(int *arr, int size)
{
return _getFoo_impl<>::func(arr, size);
}
1

Другие решения

Вы не можете хранить или генерировать тип из шаблона класса

template <int... N>
class FooImpl;

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

template <int... N>
R FooFun(A...);

заданные целые числа времени выполнения в качестве аргументов шаблона, при условии подписи функции R(A...) одинаково для всех аргументов шаблона. Обратите внимание, что A... здесь не пакет параметров шаблона; это просто заполнитель для типов ваших конкретных параметров функций, например FooFun(int, int),

Мне кажется, что эта формулировка действительно соответствует вашей проблеме, потому что у вас есть фабричная функция без входных параметров, которая возвращает указатель на объект FooImpl<N...> всегда рассматривается как Foo*так в твоем случае FooFun будет выглядеть

template <int... N>
Foo* FooFun();

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

Разница в вашем случае заключается в том, что вам нужен многомерный Справочная таблица. Я предлагаю сначала определить функцию «диспетчер» только с одним целочисленным аргументом шаблона

template <int OFFSET>
R FooDispatch(A...);

который представляет линейное смещение в многомерной таблице. В этом случае предыдущее решение относится непосредственно к FooDispatch, Затем вы должны конвертировать OFFSET к набору многомерных показателей N..., во время компиляции. Для этого вам также необходимо знать размеры таблицы, или лучше ее шаги, снова во время компиляции. Выведя аргументы N..., FooDispatch теперь могу позвонить FooFun<N...>(...),

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

Все вышесказанное подразумевает, что число измерений также известно во время компиляции, поэтому в конечном итоге функция вида

Foo* getFoo(int arr[N]);

было бы хорошо, как интерфейс, но

Foo* getFoo(int* pint, int size);

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

Наконец, обратите внимание, что использование индексов вне диапазона во время выполнения будет иметь тот же эффект, что и использование индексов вне диапазона в обычном массиве C.

0

По вопросам рекламы [email protected]