【问题标题】:Using meta-programming to calculate the log2 but `compilation terminated`使用元编程计算 log2 但“编译终止”
【发布时间】:2018-10-21 06:38:30
【问题描述】:

我是 TMP 新手,我编写了一个程序,使用元编程来计算 log2。我写了一个模板结构power2 来计算功率,一个模板类log2arr 里面有一个数组来保存结果,以及一个嵌入式模板结构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;
    }
}

但是编译器只告诉我compilation terminated.

这是什么意思?我该如何解决?

任何帮助将不胜感激。

【问题讨论】:

  • 使用更好的编译器,它可以在没有 ICE 的情况下为您提供正确的错误。如果您想快速访问其中的许多内容,请尝试使用 godbolt.org 之类的在线服务

标签: c++ c++11 templates template-meta-programming template-specialization


【解决方案1】:

您的代码存在一些问题,我将展示其中的一些问题,不分先后。

(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) 如果你从getArr() 返回一个int *,你会丢失log2Arr 类中关于数组的信息;所以不适用于基于范围的 for 循环 (for(auto i : a.getArr()))。

很遗憾,您无法返回 C 样式的数组(您无法返回 arr 本身)。

但是您使用的是 C++11 或更新版本(您只标记了 C++,但您使用的是基于范围的 for 循环,因此您至少使用的是 C++11)所以我强烈建议您定义 @987654332 @ 作为 std::array&lt;int, N&gt;,而不是 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&lt;1&gt;

    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&lt;I&gt; 初始化 arr[I]log&lt;1&gt; 未初始化任何内容,您的 int arr[N] 包含未初始化的 arr[0]arr[1] 值。

您可以将这些值初始化为零写入

  int arr[N] {};

或(使用std::array&lt;int, N&gt;

  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;
 }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-25
    • 2011-03-06
    • 1970-01-01
    相关资源
    最近更新 更多