В вашем коде есть некоторые проблемы, и я покажу некоторые из них в произвольном порядке.
(1) полные специализации не допускаются внутри структуры / класса;поэтому вы не можете полностью специализироваться log2
внутри log2arr
.
Вы можете мигрировать log2
за пределы log2arr
или, если вы действительно хотите сохранить его внутри log2arr
, вы можете преобразовать полную специализациюв эквивалентной частичной специализации (легально внутри структуры / класса);Например, следующим образом
template <int I, typename = std::true_type>
struct log2
{
// body of the struct
};
template <int I>
struct log2<I, std::integral_constant<bool, I == 1>>
{
// body of the struct specialization
};
(2) если вы вернете int *
из getArr()
, вы потеряете информацию о массиве внутри log2Arr
class;поэтому не работает диапазон, основанный на цикле (for(auto i : a.getArr())
).
К сожалению, вы не можете вернуть массив в стиле C (вы не можете вернуть arr
сам).
Но вы используете C ++ 11 или новее (вы пометили только C ++, но вы используете диапазон, основанный на цикле, поэтому вы используете по крайней мере C ++ 11), поэтому я настоятельно рекомендую вам определить arr
какstd::array<int, N>
, не как массив в стиле C (не int arr[N]
).И я настоятельно рекомендую вам вернуть ссылку на саму arr
(с помощью std::array
вы можете сделать это)
private:
using arrT = std::array<int, N>;
arrT arr {};
// ...
public:
arrT & getArr ()
{ /* ... */ return arr; }
, и я также предлагаю добавить getArr()
для const
объектов
arrT const & getArr () const
{ /* ... */ return arr; }
(3) вы не можете управлять массивом arr
(не статическим членом log2Arr
) внутри метода встроенной структуры log2
void set()
{
_arr.set();
arr[i] = value; // <--- arr is inaccessible
}
Aвозможное решение - передать arr
в качестве ссылки, поэтому
void set (arrT & a) // arrT = std::array<int, N>
{
_arr.set(a);
a[i] = value;
}
и (в log2<1>
)
void set (arrT &) {}
Очевидно, вам нужно вызвать set()
, передав arr
в качестве аргументаТак что
log2<N>().set(arr)
(4) инициализация arr
внутри getArr()
- плохая идея (ИМХО), потому что вы инициализируете arr
каждый раз, когда звоните getArr()
.
Более того: вы не можете использовать arr
внутри другого метода (если вы хотите добавить другой) без инициализации его внутри другого метода.
Предложение: инициализировать arr
, один раз для всех, внутриявный конструктор;Например,
log2arr ()
{ log2<N>().set(arr); }
, так что ваши getArr()
методы просто становятся
arrT & getArr ()
{ return arr; }
arrT const & getArr () const
{ return arr; }
(5) с log2<I>
, которые инициализируют arr[I]
и log<1>
, которые ничего не инициализируют, ваш int arr[N]
содержит значения arr[0]
и arr[1]
, которые не являются инициализированными.
Вы можете инициализировать эти значения, записывая ноль
int arr[N] {};
или (используя std::array<int, N>
)
using arrT = std::array<int, N>;
arrT arr {};
// ^^ <--- initialize all to zero
но вы должны решить, как инициализировать в arr[0]
и arr[1]
(6) нет необходимости инициализировать a
следующим образом
log2arr<4> a = log2arr<4>();
Вы можете просто написать
log2arr<4> a;
--------------------------------------
Ниже приведен модифицированный код
#include <array>
#include <iostream>
template <int I>
struct power2
{ enum { value = (1 << I) }; };
template <int N>
class log2arr
{
private:
using arrT = std::array<int, N>;
arrT arr {};
template <int I, typename = std::true_type>
struct log2
{
log2<I-1> _arr;
enum { value = log2<I-1>::value
+ (power2<log2<I-1>::value>::value == I) };
void print ()
{ _arr.print(); std::cout << value << std::endl; }
void set (arrT & a)
{ _arr.set(a); a[I] = value; }
};
template <int I>
struct log2<I, std::integral_constant<bool, I == 1>>
{
enum { value = 1 };
void print() {}
void set(arrT &) {}
};
public:
log2arr ()
{ log2<N>().set(arr); }
arrT & getArr ()
{ return arr; }
arrT const & getArr () const
{ return arr; }
};
int main ()
{
log2arr<4> a;
for ( auto i : a.getArr() )
std::cout << i;
std::cout << std::endl;
}