Вот моя проблема, я имею дело с n-мерными данными. Скажем, n = 2 для простоты. Также у меня есть алгоритм для 1D данных. Чтобы расширить этот алгоритм для двумерной задачи, я могу сделать
for each row
apply algorithm
Однако, если я хочу применить этот алгоритм для каждого столбца, мне нужно написать новую функцию
for each column
apply algorithm
Например, предположим, у меня есть функция:
void func(vector<T> &vec);
Затем, чтобы применить эту функцию к вектору, я могу просто вызвать эту функцию:
vector<T> vec;
func(vec);
Для 3D-данных:
T multiArray[l][m][n];
Насколько я знаю, если я хочу применить вышеуказанную функцию для всех векторов в первом измерении, я сделаю:
for(int j=0;j<m;j++){
for(int k=0;k<n;k++){
vector<T> singleArray;
for(int i=0;i<l;i++){
singleArray.push_back(multiArray[i][j][k]);
}
func(singleArray);
}
}
Однако для тех же данных, если я хочу применить вышеуказанную функцию для всех векторов в третьем измерении, мне нужно переписать ее как:
for(int i=0;i<l;i++){
for(int j=0;j<m;j++){
vector<T> singleArray;
for(int k=0;k<n;k++){
singleArray.push_back(multiArray[i][j][k]);
}
func(singleArray);
}
}
По сути, все одинаково, за исключением итераторов в каждом цикле for. Я надеюсь, что есть несколько способов реализовать эти два вычисления с помощью одной функции.
Спасибо
Я не знаю общего решения, но вы можете решить вашу конкретную проблему (использовать первый, второй или третий индекс или …), используя ссылку.
В трехмерном случае сначала вы можете объявить переменные цикла (i
, j
а также k
)
std::size_t i, j, k;
Далее вы можете «связать» другую переменную (r
) чтобы i
, j
или же k
согласно значению шаблона I
std::size_t & r = (I == 0U ? i : (I == 1U ? j : k));
Ниже приведен компилируемый пример
#include <vector>
#include <iostream>
template <std::size_t I>
void func (std::vector<std::vector<std::vector<double> > > & d)
{
std::size_t i, j, k;
std::size_t & r = (I == 0U ? i : (I == 1U ? j : k));
for ( i = 0U ; i < d.size() ; ++i )
for ( j = 0U ; j < d[i].size() ; ++j )
for ( k = 0U ; k < d[i][j].size() ; ++k )
d[i][j][k] += r+1;
}
int main()
{
std::vector<std::vector<std::vector<double> > > data;
// some data in data
func<0>(data); // r is i
func<1>(data); // r is j
func<2>(data); // r is k
}
— РЕДАКТИРОВАТЬ —
ОП спрашивать
в любом случае, что эта функция может работать для произвольного измерения?
Нет.
Не этот функция.
Но я предлагаю совершенно другое (и более сложное) решение. Я пишу это, но не прошу меня проверить, действительно ли это работает.
Идея больше не основана на ссылках, а на специализации шаблонов.
На этот раз индекс шаблона основан на 1: используйте значение шаблона 1
если вы хотите перехватить первый индекс (например, x
), 2
если вы хотите перехватить второй индекс (например, y
), так далее.
Так вы звоните
foo<1U>(data1); // r is the first index
для одномерного вектора,
foo<1U>(data2); // r is the first index
foo<2U>(data2); // r is the second index
для 2D вектора и т. д.
Если вы позвоните
foo<I>(data)
где I
больше, чем размерность data
, вы получаете ошибку компиляции.
Если вы позвоните
foo<0>(data)
вы получаете ошибку компиляции, но только если вы компилируете C ++ 11 или новее (с C ++ 98 r
стать нулем; но вы можете добавить assert()
чтобы получить ошибку во время выполнения).
Пример
#include <vector>
#include <iostream>
template <std::size_t I>
struct bar
{
template <typename T>
static void baz (std::vector<T> & v, std::size_t)
{
for ( std::size_t i = 0U ; i < v.size() ; ++i )
bar<I-1U>::baz(v[i], i);
}
};
template <>
struct bar<0U>
{
template <typename T>
static void baz (std::vector<T> & v, std::size_t r)
{
for ( std::size_t i = 0U ; i < v.size() ; ++i )
baz(v[i], r);
}
static void baz (double & d, std::size_t r)
{ d += r + 1U; }
};template <std::size_t I, typename V>
void foo (V & v)
{
#if __cplusplus >= 201103L
static_assert(I > 0U, "!"); // c++11 or newer
#endif
bar<I>::baz(v, 0U);
}
int main()
{
std::vector<double > data1;
std::vector<std::vector<double> > data2;
std::vector<std::vector<std::vector<double> > > data3;
// some data in data1, data2 and data3
// foo<0U>(data1); // compilation error in C++11 or newer
foo<1U>(data1); // r is the first index
// foo<2U>(data1); // compilation error
// foo<0U>(data2); // compilation error in C++11 or newer
foo<1U>(data2); // r is the first index
foo<2U>(data2); // r is the second index
// foo<3U>(data2); // compilation error
// foo<0U>(data3); // compilation error in C++11 or newer
foo<1U>(data3); // r is the first index
foo<2U>(data3); // r is the second index
foo<3U>(data3); // r is the third index
// foo<4U>(data3); // compilation error
}
Других решений пока нет …