模板化类问题中的静态分配器('sizeof'到不完整类型的无效应用程序)

时间:2016-04-05 09:21:40

标签: c++ templates static initialization

我编辑了原始问题。

我试图在模板化的类中使用自我实现的静态分配器,我收到此错误:

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++仅接受非模板化版本。

2 个答案:

答案 0 :(得分:1)

您的问题是您的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;

答案 1 :(得分:1)

我认为事情的核心foo_c不完整,因为它的大小取决于allocator_t的大小,但allocator_t取决于foo_c的大小。< / p>

如果我们改为foo_c指向allocator_t<foo_c>,那么事情就可以了,因为这是我们可以用不完整类型做的少数事情之一。

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,然后放置它的定义,但我不确定这是定义的行为。