Можно ли реализовать операцию по столбцам и работу по строкам с помощью одной шаблонной функции?

Вот моя проблема, я имею дело с 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. Я надеюсь, что есть несколько способов реализовать эти два вычисления с помощью одной функции.

Спасибо

1

Решение

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

В трехмерном случае сначала вы можете объявить переменные цикла (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
}
0

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

Других решений пока нет …

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