Recently I am having many problem with typedef and incomplete type when I changed certain containers, allocators in my code.
What I had previously
struct foo;//incomplete type.
typedef std::vector<foo> all_foos;
typedef all_foos::reference foo_ref;
Though not completely not sure whether the above lines are legal, but this worked on every implementation I used. When I thought that I can do the job with std::tr1::array
, changed the above two lines with
typedef std::tr1::array<foo,5> all_foos;
typedef all_foos::reference foo_ref;
Here everything breaks, as the compiler tries to instantiate array
and fails as foo
is incomplete type. What all I needed is a reference to foo
, and not much interested on 'other parts' of the array. foo will definitely be completely available when I create such an array.
The same is problem when typedef std::allocator<foo>::pointer foo_ptr
got replaced by typedef stack_alloc<foo,10>::pointer foo_ptr
. where a stack_alloc
implementation is like
template<typename T,unsigned N>
struct stack_alloc
{
typedef T* pointer;
typedef std::tr1::aligned_storage<sizeof(T)*N, std::tr1::alignment_of<T>::value> buffer;
};
Presuming that, value_type
, pointer
, reference
, iterator
etc does not depend on the completeness of T
, and knowing that the class can not be instantiate without complete type, how such typedef can be made in generic way independent of specific container or allocator?
NOTE:
vector
rather than replacing it with std::array
, though the problem remains same.stack_alloc
code is far from complete, and only shows the part of the problem.all_foos
with incomplete foo
.struct foo{ foo_ptr p;};
can not be defined. Though probably foo_ref
can not be anything other than foo&
, but foo_ptr
can be. Surprisingly GCC implementation doesn't have nested pointer type for tr1::array
.A type must be complete to be used in a standard container, or the behavior is undefined (§17.4.3.6/2). So the only standard solution is to not make that typedef
until the class is defined.
I don't get what the intermediate container is for:
struct foo;//incomplete type.
typedef foo& foo_ref;
In any case, you'll just have to have the complete type defined first, really. To get a typedef
defined in a class, that class must be instantiated, which means the entire thing must be able to use T
as desired.
For example, stack_alloc
must have T
be a complete type (for sizeof(T)
to work), otherwise the class cannot be instantiated. If the class can't be instantiated, you cannot get the typedef
out of it. Ergo, you'll never get the typedef
out of it if T
is incomplete.
Compiller doesn't know the size of incomplete type, therefore it can not instantiate it nor allocate some memory for it. Having a pointer to object (like typedef std::tr1::array<foo*, 5> all_foos;
) instead of instance of the object itself solves this issue.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With