【问题标题】:Static allocator in a templated class issue (invalid application of 'sizeof' to incomplete type)模板类问题中的静态分配器(“sizeof”对不完整类型的无效应用)
【发布时间】:2016-04-05 09:21:39
【问题描述】:

我已经编辑了原始问题。


我尝试在模板类中使用自行实现的静态分配器,但出现此错误:

error: invalid application of 'sizeof' to incomplete type

我试图最小化代码但仍然保留错误,这就是我得到的:

template<typename T>
struct allocator_t {
  unsigned char blk[sizeof(T)];
};

template<typename t_value_t, int t_max_nodes>
class foo_c {
private:
  typedef allocator_t<foo_c> bar_allocator_t;
  static bar_allocator_t m_allocator;
};

template<typename t_value_t, int t_max_nodes>
typename foo_c<t_value_t, t_max_nodes>::bar_allocator_t
  foo_c<t_value_t, t_max_nodes>::bar_t::m_allocator;

struct some_t {
  explicit some_t(void) {}
};

void func(void) {
  foo_c<some_t, 10> a;
}

完整的错误堆栈如下:

template_static_example.cc: In instantiation of 'allocator_t<foo_c<some_t, 10> >':
template_static_example.cc:21:2: instantiated from 'foo_c<some_t, 10>'
template_static_example.cc:30:21: instantiated from here
template_static_example.cc:3:30: error: invalid application of 'sizeof' to incomplete type 'foo_c<some_t, 10>'

我有其他模块基本上使用相同的技术,一切都很棒。

这些模块和我正在尝试制作的新模块之间的区别在于,新模块是模板化的,实际上,上面的代码(减去模板)编译时没有错误:

template<typename T>
struct allocator_t {
  unsigned char blk[sizeof(T)];
};

class foo_c {
private:
  typedef allocator_t<foo_c> bar_allocator_t;
  static bar_allocator_t m_allocator;
};

foo_c::bar_allocator_t foo_c::m_allocator;

struct some_t {
  explicit some_t(void) {}
};

void func(void) {
  foo_c a;
}

我可以提供的另一个输入是,当我使用clang 编译时,两者都编译没有错误。 g++ 但是,只接受非模板版本。

【问题讨论】:

  • 您的示例可以最小化为struct foo { int bar[sizeof(foo)]; };,您试图在其定义结束之前获得bar_t 的大小。
  • @user657267 谢谢,我明白这一点,但请查看更新后的问题并尝试解释为什么没有模板这是有效的。
  • @AndyThomas:你仍然有同样的问题。将其视为循环依赖; allocator_t 需要foo_c 的完整定义来扩展其模板,foo_c 需要allocator_t 的完整定义来扩展其模板。
  • @AndyG 那么没有模板它是如何工作的呢?
  • @AndyThomas:你可以用不完整的类型做一些事情。不幸的是,试图获得它们的大小并不是其中之一。请向我展示一个在没有模板的情况下使用相同技术的示例,我将向您展示您已对其进行了更改,以使类型不再不完整。

标签: c++ templates static initialization


【解决方案1】:

我相信foo_c 的核心是不完整的,因为它的大小取决于allocator_t 的大小,但allocator_t 取决于foo_c 的大小。

如果我们改为给 foo_c 一个指向 allocator_t&lt;foo_c&gt; 的指针,那么事情就可以工作,因为这是我们可以对不完整类型做的少数事情之一。

template<typename t_value_t, int t_max_nodes>
class foo_c {
private:
  typedef allocator_t<foo_c> bar_allocator_t;
  static std::unique_ptr<bar_allocator_t> m_allocator;
};

template<typename t_value_t, int t_max_nodes>
std::unique_ptr<typename foo_c<t_value_t, t_max_nodes>::bar_allocator_t>
  foo_c<t_value_t, t_max_nodes>::m_allocator;

Live Demo


看起来 GCC 和 Clang will compile your code 原样,只要您转发声明 allocator_t,然后稍后放置其定义,但我不确定这是定义的行为。

【讨论】:

    【解决方案2】:

    您的问题是您的bar_allocator_t 在bar_t 中声明。分配器在编译期间试图获取bar_t 的大小:

    unsigned char blk[sizeof(T)];
    

    但它还没有完成结构的定义,所以它不知道大小是多少:

    struct bar_t {
      explicit bar_t(void) {};
      ~bar_t(void);
    
    private:
      typedef allocator_t<bar_t> bar_allocator_t;
      static bar_allocator_t m_allocator; // We don't know the size of `bar_t` here
    };
    

    我不确定哪种解决方案适合您,但您可能需要将分配器移到结构之外,或者您可以使用动态内存:

    template<typename t_value_t, int t_max_nodes>
    class foo_c {
       private:
       struct bar_t {
       explicit bar_t(void) {};    
        ~bar_t(void);
    
      private:
        typedef allocator_t<bar_t> bar_allocator_t;
        static bar_allocator_t * m_allocator;
      };
    
      bar_t m_root;
    };
    
    template<typename t_value_t, int t_max_nodes>
    typename foo_c<t_value_t, t_max_nodes>::bar_t::bar_allocator_t *
    foo_c<t_value_t, t_max_nodes>::bar_t::m_allocator = 
    new typename foo_c<t_value_t, t_max_nodes>::bar_t::bar_allocator_t;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-10-09
      • 1970-01-01
      • 1970-01-01
      • 2019-11-25
      • 1970-01-01
      • 1970-01-01
      • 2013-04-05
      • 1970-01-01
      相关资源
      最近更新 更多