C ++: нет соответствующего вызова функции для конструктора? - PullRequest
0 голосов
/ 12 октября 2011

Вот объявление используемого мной конструктора:

_Task Multiplier {
    int **Z;
    int **X;
    int **Y;
    int xr, xcols_yrows, yc;
    void main() {
        for( int i = 0; i < xcols_yrows; i++ ) {
            matrixmultiply(Z, X, xr, i, Y, yc);
        }
    }

  public:
    Multiplier( int *Z[], int *X[], int *Y[], int xr, int xcols_yrows, int yc) :
        Z( Z ), X( X ), Y( Y ), xr( xr ), xcols_yrows( xcols_yrows ), yc( yc ) {}

};

И вот где оно используется:

int xrows, xcols_yrows, ycols;
// [cols][rows]
int X[xrows][xcols_yrows], Y[xcols_yrows][ycols], Z[xrows][ycols];
// start threads to multiply rows
Multiplier *multipliers[xrows];
for( int r = 0; r < xrows; r++ ) {
    multipliers[r] = new Multiplier( &Z, &X, &Y, r, xcols_yrows, ycols );
}

(все они инициализированы) Но я получаюэта странная ошибка:

q3.cc: In member function 'virtual void uMain::main()':
q3.cc:132: error: no matching function for call to 'Multiplier::Multiplier(int (*)[(((unsigned int)(((int)xrows) + -0x00000000000000001)) + 1)][(((unsigned int)(((int)ycols) + -0x00000000000000001)) + 1)], int (*)[(((unsigned int)(((int)xrows) + -0x00000000000000001)) + 1)][(((unsigned int)(((int)xcols_yrows) + -0x00000000000000001)) + 1)], int (*)[(((unsigned int)(((int)xcols_yrows) + -0x00000000000000001)) + 1)][(((unsigned int)(((int)ycols) + -0x00000000000000001)) + 1)], int&, int&, int&)'
q3.cc:37: note: candidates are: Multiplier::Multiplier(int**, int**, int**, int, int, int, UPP::uAction)
q3.cc:26: note:                 Multiplier::Multiplier(Multiplier&)
make: *** [q3.o] Error 1

Ответы [ 2 ]

2 голосов
/ 12 октября 2011

Проблема в том, что параметры функции X, Y и Z в основном ожидают array of pointers to int, но вы даете ему pointer to an array of arrays of int.

Задание параметра в видемассив (объявленный с []) распадается на объявление параметра в качестве указателя.И это нормально, поскольку переменную массива можно в основном рассматривать как указатель на первый элемент массива.

Однако это недопустимо для n-мерных массивов, поскольку компилятор должен знать, насколько широкомассив расположен вдоль второго измерения, чтобы вычислить начало следующего элемента вдоль первого измерения ... то есть, чтобы узнать, к какому месту в памяти относится X[1][0], компилятору необходимо знать, сколько элементовв X[0].

Одним из решений было бы использование указателя на начало каждой матрицы и выполнение вычислений адреса самостоятельно.Например:

Multiplier( int *Z, int *X, int *Y, int xr, int xcols_yrows, int yc) :
    Z( Z ), X( X ), Y( Y ), xr( xr ), xcols_yrows( xcols_yrows ), yc( yc ) {}
// ...
multipliers[r] = new Multiplier( &Z[0][0], &X[0][0], &Y[0][0], r, xcols_yrows, ycols );

И знайте, что X[i][j] в коде вызова на самом деле X[i*xcols_yrows+j] внутри Multiplier.

1 голос
/ 12 октября 2011

Объявление параметра int *Z[] указывает массив указателей на целые числа. Объявление члена int **Z указывает указатель на указатель (или его массив). Тип аргумента int X[xrows][xcols_yrows] - это многомерный массив без указателей вообще.

Кроме того, выделенное хранилище находится в стеке, где оно исчезнет после оператора return. Поскольку объект Multiplier назначается с new, предположительно, массив должен иметь аналогичное время жизни. Возможно, массив должен быть выделен как new в Multiplier::Multiplier, или в любом случае он должен управляться объектом unique_ptr или auto_ptr.

Существует несколько решений первой проблемы:

  1. Используйте шаблонный конструктор, который определяет размеры массива во время компиляции.
  2. Использовать массив указателей, выделенных new или calloc.
  3. Выделите одномерный массив и используйте его многомерным образом.
...