Andy Thomas
Andy Thomas

Reputation: 1309

Static allocator in a templated class issue (invalid application of 'sizeof' to incomplete type)

I have edited the original question.


I am trying to use a self-implemented static allocator inside a templated class and I'm getting this error:

error: invalid application of 'sizeof' to incomplete type

I have tried to minimize the code but still preserve the error and this is what I got:

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

The full error stack is this:

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>'

I have other modules that basically use the same technique and everything is great.

The difference between those modules and the new one I am trying to make is that the new one is templated and indeed, the above code (minus templates) is compiled without errors:

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

Another input I can give is that when I compile with clang both are compiled without errors. g++ however, accepts only the non-templated version.

Upvotes: 3

Views: 149

Answers (2)

AndyG
AndyG

Reputation: 41110

I believe that at the heart of things foo_c is incomplete because its size depends on the size of allocator_t, but allocator_t depends on the size of foo_c.

If we instead gave foo_c a pointer to a allocator_t<foo_c>, then things could work, because that is one of the few things we can do with an incomplete type.

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


It does appear that GCC and Clang will compile your code as-is so long as you forward declare allocator_t, and then place its definition later, but I'm not sure that this is defined behavior.

Upvotes: 1

Bok McDonagh
Bok McDonagh

Reputation: 1447

Your problem is that your bar_allocator_t is declared inside bar_t. The allocator is trying to get the size of bar_t during compilation:

unsigned char blk[sizeof(T)];

but it hasn't finished defining the struct yet so it doesn't know what the size is:

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

I'm not sure what solution will work for you but you probably need to move the allocator outside of the struct, or you could use dynamic memory:

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;

Upvotes: 1

Related Questions