我是TMP的新手,我使用元编程编写了一个程序来计算log2.我编写了一个模板struct power2来计算功率,一个模板类log2arr,其中包含一个数组以保存结果,还有一个嵌入式模板struct log2来计算log2值.
#include <iostream>
template <int i>
struct power2
{
enum
{
value = (1 << i)
};
};
template <int n>
class log2arr
{
int arr[n];
template <int i>
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()
{
_arr.set();
arr[i] = value;
}
};
template <>
struct log2<1>
{
enum
{
value = 1
};
void print() {}
void set() {}
};
public:
int *getArr()
{
log2<n>().set();
return arr;
}
};
int main()
{
log2arr<4> a = log2arr<4>();
for(auto i : a.getArr()){
cout << i;
}
}
但编译器只告诉我编译终止.
这是什么意思?我该如何解决?
任何帮助将不胜感激.
最佳答案 你的代码有一些问题,我会以一些特定的顺序展示它们中的一些.
(1)在struct / class中不允许完全特化;所以你不能在log2arr里面完全专门化log2.
你可以在log2arr之外迁移log2,或者,如果你真的希望将它保存在log2arr中,你可以在一个等价的部分特化中转换完全特化(在struct / class中合法);例如,如下
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)如果从getArr()返回一个int *,则会丢失有关log2Arr类中数组的信息;所以不适用于基于循环的范围(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; }
我还建议为const对象添加一个getArr()
arrT const & getArr () const
{ /* ... */ return arr; }
(3)你不能在嵌入式结构log2的方法里面管理arr数组(不是log2Arr的静态成员)
void set()
{
_arr.set();
arr[i] = value; // <--- arr is inaccessible
}
一个可能的解决方案是传递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)在getArr()内部初始化arr是一个坏主意(恕我直言),因为每次调用getArr()时都会初始化arr.
而且:你不能在另一个方法中使用arr(如果你想添加另一个方法)而不在另一个方法中初始化它.
建议:在显式的构造函数中初始化arr,一次性.通过例子
log2arr ()
{ log2<N>().set(arr); }
所以你的getArr()方法就变成了
arrT & getArr ()
{ return arr; }
arrT const & getArr () const
{ return arr; }
(5)log2< I>初始化arr [I]并记录< 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)没有需要初始化如下
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;
}