Topic: detecting incomplete type


Author: Balog Pal <pasa@lib.hu>
Date: Wed, 6 Feb 2013 01:50:31 CST
Raw View
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-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: =?ISO-8859-1?Q?Daniel_Kr=FCgler?= <daniel.kruegler@googlemail.com>
Date: Thu, 7 Feb 2013 02:08:27 CST
Raw View
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




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





Author: James Kuyper <jameskuyper@verizon.net>
Date: Thu, 7 Feb 2013 02:31:59 CST
Raw View
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.


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





Author: James Kanze <james.kanze@googlemail.com>
Date: Thu, 7 Feb 2013 02:32:32 CST
Raw View
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


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