Reputation: 1309
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
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;
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
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