Сначала я пытаюсь воспроизвести вашу ошибку при компиляции
Чтобы получить ошибку компиляции, сначала нужно сделать много изменений в коде, который вы дали, потому что он содержит несколько других ошибок, в следующий раз будьте осторожнее с нами; -)
Так, например, с:
#include <stddef.h> // size_t
template <typename T, size_t N>
struct NDimensionalArray {
typedef typename NDimensionalArray<T, N - 1>::type * type;
};
template<typename T>
struct NDimensionalArray<T, 1> {
typedef T * type;
};
template <typename T, size_t N>
class NDimArray {
public:
typename NDimensionalArray<T, N>::type arr{ nullptr };
NDimArray(int) {
init(arr, 0); //exception, cannot transform T*** to T*&,
//invokes T&
}
void init(T &, size_t) { }
void init(T *& arr, size_t n) {
arr = new T[n];
for (size_t i = 0; i < n; ++i)
init(arr[i], n);
}
};
int main() {
NDimArray<int, 3> arr(2);
}
Компиляция:
pi@raspberrypi:/tmp $ g++ -pedantic -Wall -Wextra c.cc
c.cc: In instantiation of ‘NDimArray<T, N>::NDimArray(int) [with T = int; unsigned int N = 3u]’:
c.cc:38:28: required from here
c.cc:21:17: error: invalid conversion from ‘NDimensionalArray<int, 3u>::type {aka int***}’ to ‘int’ [-fpermissive]
init(arr, 0); //exception, cannot transform T*** to T*&,
^~~
c.cc:25:14: note: initializing argument 1 of ‘void NDimArray<T, N>::init(T&, size_t) [with T = int; unsigned int N = 3u; size_t = unsigned int]’
void init(T &, size_t) { }
^~~~
c.cc:21:17: error: cannot bind rvalue ‘(int)((NDimArray<int, 3u>*)this)->NDimArray<int, 3u>::arr’ to ‘int&’
init(arr, 0); //exception, cannot transform T*** to T*&,
^~~
pi@raspberrypi:/tmp $
Чтобы устранить ошибку компиляции, просто измените строку, в которой она появляется, замените
NDimArray(int) {
init(arr, 0); //exception, cannot transform T*** to T*&,
//invokes T&
}
от
NDimArray(int) {
init(**arr, 0);
}
потому что указатель и ссылка уже не одно и то же, поэтому нет никакого шанса с указателем на указатель, но ссылка может быть сделана из значения
Компиляция:
pi@raspberrypi:/tmp $ g++ -pedantic -Wall -Wextra c.cc
pi@raspberrypi:/tmp $
Выполнение завершается неудачно, потому что вы разыменовываете nullptr
Что вы хотите
Но код, который вы хотите (не пытаясь воспроизвести вашу ошибку), основанный на первом случае в вашем вопросе, на самом деле:
#include <stddef.h> // size_t
template<typename T, size_t N>
struct NDimensionalArray {
typedef typename NDimensionalArray<T, N - 1>::type * type;
};
template<typename T>
struct NDimensionalArray<T, 1> {
typedef T * type;
};
template<typename T>
void initializeNDimensionalArray(T &, size_t) { }
template<typename T>
void initializeNDimensionalArray(T *& arr, size_t n) {
arr = new T[n];
for (size_t i = 0; i < n; ++i)
initializeNDimensionalArray(arr[i], n);
}
template<typename T, size_t N>
class NDimArray {
public:
typename NDimensionalArray<T, N>::type arr;
NDimArray(size_t n) {
initializeNDimensionalArray(arr, n);
}
};
int main()
{
NDimArray<int, 3> nd(2);
}
Или, если вы предпочитаете вложенные определения:
#include <stddef.h> // size_t
template<typename TT, size_t NN>
class NDimArray {
template<typename T, size_t N>
struct NDimensionalArray {
typedef typename NDimensionalArray<T, N - 1>::type * type;
};
template<typename T>
struct NDimensionalArray<T, 1> {
typedef T * type;
};
template<typename T>
void initializeNDimensionalArray(T &, size_t) { }
template<typename T>
void initializeNDimensionalArray(T *& arr, size_t n) {
arr = new T[n];
for (size_t i = 0; i < n; ++i)
initializeNDimensionalArray(arr[i], n);
}
public:
typename NDimensionalArray<TT, NN>::type arr;
NDimArray(size_t n) {
initializeNDimensionalArray(arr, n);
}
};
int main()
{
NDimArray<int, 3> nd(2);
}
Для них обоих нет ошибок / предупреждений во время компиляции:
pi@raspberrypi:/tmp $ g++ -g -pedantic -Wall -Wextra a.cc
pi@raspberrypi:/tmp $
и без проблем при исполнении
pi@raspberrypi:/tmp $ ./a.out
pi@raspberrypi:/tmp $
О вашем замечании
Если вы попытаетесь инициализировать созданный объект, вы получите исключение, поэтому он не создает его должным образом.
Предупреждение, чтобы не путать роли
- параметр шаблона класса NDimArray указывает количество измерений (3 в
NDimArray<int, 3> arr(2);
)
- параметр его конструктора указывает количество элементов в каждом измерении (2 в
NDimArray<int, 3> arr(2);
)
Инициализация / распределение правильные. Пример нового определения для main :
int main()
{
const size_t dimsz = 2;
NDimArray<int, 3> nd(dimsz);
// initialize elements
for (size_t i = 0; i != dimsz; ++i)
for (size_t j = 0; j != dimsz; ++j)
for (size_t k = 0; k != dimsz; ++k)
nd.arr[i][j][k] = i*100+j*10+k;
// check
for (size_t i = 0; i != dimsz; ++i)
for (size_t j = 0; j != dimsz; ++j)
for (size_t k = 0; k != dimsz; ++k)
std::cout << "nd.arr[" << i << "][" << j << "][" << k << "] = " << nd.arr[i][j][k] << std::endl;
return 0;
}
Компиляция и исполнение:
pi@raspberrypi:/tmp $ g++ -pedantic -Wall -Wextra a.cc
pi@raspberrypi:/tmp $ ./a.out
nd.arr[0][0][0] = 0
nd.arr[0][0][1] = 1
nd.arr[0][1][0] = 10
nd.arr[0][1][1] = 11
nd.arr[1][0][0] = 100
nd.arr[1][0][1] = 101
nd.arr[1][1][0] = 110
nd.arr[1][1][1] = 111
pi@raspberrypi:/tmp $
Версия без указателей
Конечно, также возможно не использовать указатели для реализации многомерного массива, например:
#include <iostream>
template<typename T, size_t N, size_t M>
struct NDimensionalArray {
typedef typename NDimensionalArray<T, N - 1, M>::type type[M];
};
template<typename T, size_t M>
struct NDimensionalArray<T, 1, M> {
typedef T type[M];
};
template<typename T, size_t N, size_t M>
class NDimArray {
public:
typename NDimensionalArray<T, N, M>::type arr;
NDimArray() {
// nothing to do
}
};
int main()
{
const size_t dimsz = 2;
NDimArray<int, 3, dimsz> nd;
std::cout << "sizeof(nd) : " << sizeof(nd) << " (sizeof(int) : " << sizeof(int) << ")" << std::endl;
// initialize array
for (size_t i = 0; i != dimsz; ++i)
for (size_t j = 0; j != dimsz; ++j)
for (size_t k = 0; k != dimsz; ++k)
nd.arr[i][j][k] = i*100+j*10+k;
// check
for (size_t i = 0; i != dimsz; ++i)
for (size_t j = 0; j != dimsz; ++j)
for (size_t k = 0; k != dimsz; ++k)
std::cout << "nd.arr[" << i << "][" << j << "][" << k << "] = " << nd.arr[i][j][k] << std::endl;
return 0;
}
Компиляция и исполнение:
pi@raspberrypi:/tmp $ g++ -pedantic -Wall -Wextra mda.cc
pi@raspberrypi:/tmp $ ./a.out
sizeof(nd) : 32 (sizeof(int) : 4)
nd.arr[0][0][0] = 0
nd.arr[0][0][1] = 1
nd.arr[0][1][0] = 10
nd.arr[0][1][1] = 11
nd.arr[1][0][0] = 100
nd.arr[1][0][1] = 101
nd.arr[1][1][0] = 110
nd.arr[1][1][1] = 111
pi@raspberrypi:/tmp $