Почему не работает шаблон?

283
17 января 2018, 17:19

Мне нужно написать шаблон, который меняет местами диагонали матрицы. При компиляции выдает ошибку и не знаю как исправить. Подскажите.

#include <iostream>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
template <typename T>
T diagonal(T **array, int size) {
    T buf;
    for(int i=0;i<size;i++){
              buf=array[i][i];
              array[i][i]=array[i][(size-1)-i];
              array[i][(size-1)-i]=buf;
      }
      return buf;
}
int main() {
    setlocale(LC_ALL,"Russian");
    int size=3;
    int m[size][size];
      for(int i=0;i<size;++i){
            for(int j=0;j<size;++j){
                    cout << "ВВод " << i <<" " << j << ":";
                  cin>>m[i][j];
              }
}
     diagonal(m,size);
      for(int i=0;i<size;++i){
             for(int j=0;j<size;++j)
                    cout<<m[i][j]<<' ';
             cout<<endl;
      }
      system("pause");
      return 0;
}
Answer 1

Основная ошибка не имеет отношения к шаблонам вообще. Вы, очевидно, полагаете, что к массиву вида T a[m][n] можно доступаться через "двойной указатель" T **p. Это не так. Эти типы никак не связаны вообще. Встроенный двухмерный массив в С/С++ никак не совместим с "двойным указателем".

А что желать дальше зависит от ваших намерений. Можно вообще написать просто

template <typename T>
void diagonal(T &array, int size) {
    std::decay_t<decltype(array[0][0])> buf;
    for(int i=0;i<size;i++){
              buf=array[i][i];
              array[i][i]=array[i][(size-1)-i];
              array[i][(size-1)-i]=buf;
      }
}

или

template <typename T>
void diagonal(T &array, int size) 
{
  using std::swap;
  for (int i = 0; i < size; ++i)
    swap(array[i][i], array[i][size - 1 - i]);
}

тем самым соблюдя принцип "duck typing" шаблонного программирования: все, что нас интересует, это чтобы аргумент поддерживал lvalue выражения вида array[i][j], а уж какой конкретно тип имеет array и как он внутренне устроен нам не интересно.

(Кстати, зачем вы возвращаете последний buf из функции мне не совсем ясно.)

Но если вы хотите использовать именно T **, то от встроенного массива T a[m][n] в качестве аргумента придется отказаться. Придется строить вручную jagged array, т.е. массив указателей на массивы.

Это во-первых. Во-вторых, в С++ нет и никогда не было такого

int size=3;
int m[size][size];

Размер массива в С++ обязан быть константой времени компиляции. Даже если ваш компилятор поддерживает подобные расширенные объявления, мой вариант выше но позволить использовать такой нестандартный тип массива в качестве параметра шаблона.

Answer 2

T** реализуется как массив указателей на одномерные массивы, а T[][] как массив длиной size*size, отсюда два варианта на скорую руку

  1. Изменить m на динамический массив

    int **m = new int*[size];
    for (int i = 0; i < size; i++) m[i] = new int[size];
    
  2. Поправить шаблон и вызов

    template <typename T, int size> void diagonal(T array[size][size]) {...}
    diagonal<int, size>(m);
    

Может есть варианты по красивее, но на ночь не вспомнил.

  1. Можно сделать template <typename T> void diagonal(T *array, int size) { и работать с адресацией типа i*size+j
Answer 3

Для начала следует избавится от массивов в стиле С. Вместо них следует использовать ::std::array. Тогда функцию можно записать вот так (тип и размер выводятся):

#include <array>
#include <cstddef>
template<typename T, ::std::size_t size> void // ничего не возвращаем
diagonal(::std::array<::std::array<T, size>, size> & mat)
...
constexpr const ::std::size_t size{3}; // размер массива должен быть константой времени компиляции в любом случае
::std::array<::std::array<int, size>, size> m;

Если же хочется непременно с обычными массивами, то можно модифицировать так:

template<typename T, ::std::size_t size> void
diagonal(T ( & mat )[size][size])
READ ALSO
сортировка изображений

сортировка изображений

Сравнил попарно все изображения - получается матрица чисел (для удобства сжаты до 0-254) N x N, как теперь упорядочить чтобы похожие были рядом...

318
gdb отладка многопоточного приложения

gdb отладка многопоточного приложения

здравствуйте, возникла необходимость научиться отлаживать многопоточное приложение через gdb

410
c++ UDP Win Linux

c++ UDP Win Linux

Я хочу создать обёртку над сокетами в виде 2х простых классовНа подобии QTUdp

312
отсутствуют имена функция в выводе gdb

отсутствуют имена функция в выводе gdb

Использую данную функция для вывода stacktrace

281