Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

detecting incomplete type

122 views
Skip to first unread message

Balog Pal

unread,
Feb 6, 2013, 2:50:31 AM2/6/13
to

What is a standard way to tell whether a type is complete or not? In a
way usable in say static_assert?

In boost code I saw sizeof(T) used that worked fine on gcc and msvc
which make that 0. But I recently read the section on sizeof that
tells it used with incomplete type makes the program ill-formed.

So what to do then? I looked through type_traits for no help.

And a related question: why is the sizeof behavior of the mentioned
compilers not the standard one? I wondered that if we had
is_complete<T> in type_traits it would probably impose ODR violation
in a pure library solution. While sizeof would just work, and even
follow established practice.




--
[ comp.std.c++ is moderated. To submit articles, try posting with your ]
[ newsreader. If that fails, use mailto:std-cpp...@vandevoorde.com ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]

Daniel Krügler

unread,
Feb 7, 2013, 3:08:27 AM2/7/13
to

On 2013-02-06 08:50, Balog Pal wrote:
>
> What is a standard way to tell whether a type is complete or not? In a
> way usable in say static_assert?


sizeof(T) is a good indicator.

> In boost code I saw sizeof(T) used that worked fine on gcc and msvc
> which make that 0.


The latter behaviour is non-conforming. It should be ill-formed.

> But I recently read the section on sizeof that
> tells it used with incomplete type makes the program ill-formed.


Correct, therefore it *can* be used in sfinae conditions, because
these are defined in terms of a program that would be ill-formed. But
I'm strongly advocating against this kind of usage, see below.

> So what to do then? I looked through type_traits for no help.


Testing for an incomplete type should not be done by a trait, because
this trait could easily lead to ODR violations in your program. Except
for corner-cases (such as void), only a small subset of types
*remains* incomplete for the rest of the program. This means, if two
places in your program instantiate the trait is_incomplete<T> for the
same type T but that is incomplete in one place and complete in
another, your program undergoes undefined behaviour.

As an example, consider:

template<class T>
struct is_incomplete
{
template<class U, int = sizeof(U)>
static char test(int);

template<class>
static char(&test(...))[2];

static const bool value = sizeof(test<T>(0)) == 2;
};

struct Ukn;

static_assert(is_incomplete<void>::value, "Expected incomplete type");
static_assert(is_incomplete<Ukn>::value, "Expected incomplete type");
static_assert(is_incomplete<int[]>::value, "Expected incomplete type");
static_assert(is_incomplete<Ukn[]>::value, "Expected incomplete type");
static_assert(is_incomplete<Ukn[1]>::value, "Expected incomplete type");

struct Ukn{};

static_assert(!is_incomplete<Ukn>::value, "Expected complete type");
static_assert(!is_incomplete<Ukn[1]>::value, "Expected complete type");

> And a related question: why is the sizeof behavior of the mentioned
> compilers not the standard one?


Well, compilers are buggy, so what? The standard is pretty clear on that issue:

"The sizeof operator shall not be applied to an expression that has
function or incomplete type,"

The MS compiler is simply broken in this regard.

> I wondered that if we had
> is_complete<T> in type_traits it would probably impose ODR violation
> in a pure library solution.


It certainly would, see above. And the brokenness is not restricted to
the trait itself. It would easly make user-defined templates broken
that depends on this trait.

> While sizeof would just work, and even
> follow established practice.


sizeof isn't a solution for this, unless you want to make your program
ill-formed, when the condition is not satisfied (whichever).

HTH & Greetings from Bremen,

Daniel Kr�gler

James Kuyper

unread,
Feb 7, 2013, 3:31:59 AM2/7/13
to

On 02/06/2013 02:50 AM, Balog Pal wrote:
>
> What is a standard way to tell whether a type is complete or not? In a
> way usable in say static_assert?

It's trivial to determine at compile time whether a type is complete by
writing code for which a diagnostic is required if the type is
incomplete. However, it sounds like you want a method that can be used
in program that compiles and executes successfully. I don't know of any
standard way to do that.

...
> So what to do then? I looked through type_traits for no help.

A few of the type_traits don't require that the type they are
instantiated for be complete (all of the ones in table 48, plus
is_const, is_volatile, is_signed, and is_unsigned), but offhand I can't
come up with any construct that has standard-defined behavior for an
incomplete type which is different from that required if the type had
been complete.

James Kanze

unread,
Feb 7, 2013, 3:32:32 AM2/7/13
to

On Wednesday, February 6, 2013 7:50:31 AM UTC, Balog Pal wrote:
> What is a standard way to tell whether a type is complete or not? In a
> way usable in say static_assert?

> In boost code I saw sizeof(T) used that worked fine on gcc and msvc
> which make that 0. But I recently read the section on sizeof that
> tells it used with incomplete type makes the program ill-formed.

SFINAE should help here. Something along the lines of:

template <typename T>
class Derived : public T {};

TrueType discrim( Derived<T>* );
FalseTpe discrim( ... );

and then something like `sizeof( discrim<T>( 0 ) )`. If the
type is incomplete, the instantiation of Derived<T> fails,

--
James
0 new messages