Как заставить функцию получать многомерный массив произвольного размера в C ++? - PullRequest
2 голосов
/ 01 марта 2011

Я пытался создать функцию, которая принимает матрицу в качестве входных данных и выводит некоторую ее функцию в C ++.Но я хочу, чтобы он работал на матрице произвольного размера mxn.т.е. я не могу указать в аргументах функции значения n (двойная матрица [] [n]).Потому что п будет произвольным.Есть ли способ передать произвольный mxn 2-мерный массив функции?Заранее спасибо.-indiajoe

Ответы [ 4 ]

7 голосов
/ 01 марта 2011
template <typename T, size_t W, size_t H>
void foo(T (&array)[W][H]) {
   // Do stuff with array here
}
2 голосов
/ 01 марта 2011

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

class matrix
{
    double* values;
    size_t m;
    size_t n;
public:
    matrix(size_t m_, size_t n_)
    : m(m_), n_(n)
    {
        values = new double[m * n];
    }

    ~matrix()
    {
        delete[] values;
    }

    double& operator(size_t i, size_t j)
    {
        assert(i < m);
        assert(j < n);
        return values[i + m * j];
    }

    const double& operator(size_t i, size_t j) const
    {
        assert(i < m);
        assert(j < n);
        return values[i + m * j];
    }
private:
    matrix(const matrix&);
    matrix& operator =(const matrix&);
};

void function(const matrix& matrix);

Если вы не хотите использовать класс, а ваши данные хранятся линейно (как в моем классе матрицы), вы можете просто передать указатель на двойное число, и размеры:

void function(double* values, size_t m, size_t n);

Если вы действительно хотите использовать double [m] [n] и иметь функцию, принимающую матрицу любого размера, вы можете преобразовать ее вручную в double **, выполнив что-то вроде этого:

void function(double** lines, size_t m, size_t n);

void client()
{
    const size_t m = ...;
    const size_t n = ...;
    double matrix[m][n];

    double* temporary[m];
    for (size_t i = 0; i < m; ++ i) {
        temporary[i] = &matrix[i][0];
    }

    function(temporary, m, n);
}

Или, используя функцию шаблона для преобразования:

void function(double** array, size_t m, size_t n);

template < size_t M, size_t N >
void function(double array[M][N]) {
    double* temporary[M];
    for (size_t i = 0; i < M; ++ i) {
        temporary[i] = &array[i][0];
    }
    function(temporary, M, N);
}

Это потому, что массив может затухать только один раз до указателя (то есть двойной [n] распад до удвоенного *, но двойной [m] [n] распад до удвоенного * [n]).

1 голос
/ 01 марта 2011

используя стандартную библиотеку C ++, вы можете сделать это:

typedef std::vector<double> Dim;
typedef std::vector<Dim> Matrix;

void workOnMatrix(Matrix& matrix)
{

}

РЕДАКТИРОВАТЬ: я удаляю ссылку на STL , поскольку SGI STL и Стандартная библиотека C ++ - это не одно и то же. Кажется, что они настолько разные, что их нельзя принимать друг за друга.

0 голосов
/ 01 марта 2011

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

Вы не можете использовать интерфейс double**, как вы узнали.Вы можете привести к этому типу, но тогда вам также понадобится передать информацию о размере, чтобы вы могли:

my_ptrptr[row * col_size][col];

Вы должны четко указывать размеры, подобные этому, потому что компилятор больше не знает, что оннужно.

Лучший ответ на вашу проблему - не делать это таким образом.Используйте STL, чтобы вам не приходилось иметь дело с таким хреновым дерьмом, как это.Воспользуйтесь ответом Стефана.

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

template < typename Iter >
void fun(Iter begin, Iter end)
{
  // begin[x][y]... (*begin)[y]...++begin, etc...
}
...
double arr[arr_row_count][arr_col_count];
fun(arr, arr+arr_row_count);

Это имеет главноеПреимущество работы с НИЧЕГО, что выглядит как массив массивов.Это означает, что он станет отличным «промежуточным» методом, который вы можете использовать с вашими типами double[][] до тех пор, пока не начнете использовать что-то лучше, например std::vector и / или boost::array.Сделай так, как делает Томалак, и ты не сможешь сделать это позже ... еще одна причина не использовать этот метод.

...