#c #variadic-templates #variadic-functions
#c #переменные-шаблоны #вариационные функции
Вопрос:
У меня возникли проблемы с построением переменной функции, которая выполняет определенную задачу. Для моего конкретного примера я использую матрицы 2×2, но вы можете себе представить, что моя проблема распространяется на многие типы данных. Кроме того, для моего примера «глаз» — это идентификационная матрица 2×2.
Хорошо, итак, я хотел бы создать переменную функцию f, входные данные которой могут быть (чтобы привести 3 примера):
f(Y, 2, Z, 5, X, 3)
f(X, 4)
f(X, 2, Y, 1)
где X, Y, Z — матрицы, а числа — положительные целые числа. Она должна возвращать следующие псевдокодовые продукты kronecker соответственно:
KroneckerProduct(eye, Y, X, eye, Z)
KroneckerProduct(eye, eye, eye, X)
KroneckerProduct(Y, X)
Таким образом, по сути, он применяет матрицу в позиции в KroneckerProduct, указанной int, которая следует за матрицей, и заполняет идентификационные матрицы между ними.
Из-за моей неопытности с вариационными функциями я не продвинулся далеко с этим. Моя самая большая проблема — заставить «рекурсивный» шаг переменной функции делать то, что мне нужно (см. Комментарии в конце):
template<typename M, typename I, typename... Args>
arma::mat f(M matrix, I position, Args... args)
{
std::vector<arma::mat> matrixList;
while(position > matrixList.size())
{
matrixList.push_back(eye<arma::mat>(2,2));
}
matrixList(position-1) = matrix;
//Up until here, it's satisfied the first pair of arguments.
//However, if I call f(args...) now, it'll just re-initialize matrixList
}
Есть ли обходной путь, который мне не хватает?
Комментарии:
1. Это точно такой же обходной путь, как и «обычная» рекурсивная функция 🙂
2. Вы предполагаете, что материал после объявления matrixList должен быть помещен в другую функцию g(std::vector<arma::mat>amp; matrixList, аргументы …) и выполнять рекурсию внутри g? Насколько я понимаю вариационные шаблоны, поскольку g имеет только один аргумент, предшествующий аргументам …, разве аргументы не будут распаковываться только по одному за раз? Мне нужно, чтобы они распаковывались по два за раз, чтобы задания имели смысл.
Ответ №1:
Я не знаю, как вы собираетесь вычислять возвращаемое значение (я пока не разбираюсь в такой математике), но если вы вычислите его из финала matrixList
, вы можете создать оболочку вокруг функции:
template<typename... Args>
arma::mat calculateSomething(Argsamp;amp;... args) {
std::vector<arma::mat> list;
f(list, std::forward<Args...>(args...)); //First argument for recursion
//Calculate return value
return return_value;
};
И f
будет выглядеть так:
//Default case with just 1 argument
void f(std::vector<arma::mat>amp;) {}
template<typename M, typename I, typename... Ts>
void f(std::vector<arma::mat>amp; matrixList, M matrix, I position, Ts... args)
{
while(position > matrixList.size())
{
matrixList.push_back(eye<arma::mat>(2,2));
}
//This is not valid syntax, no idea what you are trying to do here
//matrixList(position-1) = matrix;
//recursive call
f(matrixList, args...);
}
Комментарии:
1. Спасибо, это заставило его работать, хотя я все еще не до конца понимаю, как работает пересылка… Мне нужно прочитать об этом. Я опубликую готовый фрагмент кода.
Ответ №2:
Основываясь на предложениях Rakete1111, это код, который я предполагал, что он будет работать. Он генерирует взаимодействия Гейзенберга с k-кубитами.
#include <iostream>
#include <armadillo>
const arma::cx_mat eye = "(1,0) (0,0); (0,0) (1,0)";
const arma::cx_mat sx = "(0,0) (1,0); (1,0) (0,0)";
const arma::cx_mat sy = "(0,0) (0,-1); (0,1) (0,0)";
const arma::cx_mat sz = "(1,0) (0,0); (0,0) (-1,0)";
void ArgsToMatrixList(std::vector<arma::cx_mat>amp;) {}
template<typename M, typename I, typename... Ts>
void ArgsToMatrixList(std::vector<arma::cx_mat>amp; matrixList, M matrix, I position, Ts... args)
{
while(position > matrixList.size())
{
matrixList.push_back(eye);
}
matrixList[position - 1] = matrix;
ArgsToMatrixList(matrixList, args...);
}
template<typename... Args>
arma::cx_mat J(Argsamp;amp;... args)
{
std::vector<arma::cx_mat> list;
ArgsToMatrixList(list, std::forward<Args>(args)...); //First argument for recursion
//Calculate return value
arma::cx_mat return_value = list.front();
for(int i = 1; i < list.size(); i)
{
return_value = arma::kron(return_value, list[i]);
}
return return_value;
}
int main(int argc, const char * argv[]) {
arma::cx_mat example = J(sx, 1, sy, 2, sz, 3);
std::cout << example << std::endl;
return 0;
}