Feature Proposal: Explicitly declare a struct (or class) as POD

J

jmucchiello

I posted this to comp.std.c++ last week and it never showed up so I'll
post it here to see if there's any interest. Sorry if that's against
the rules but I don't know where a FAQ might be.
-------
Hi, I have a proposal for a language addition. I realize it is far
too late
for this idea in C++0x but I think it would be a good addition to the
language.

My proposal is to make it possible to explicitly mark a struct (or
class) as
plain-old-data (POD). Currently, the language specification states the
rules for
determining IF a struct (or class) is POD. While these rules were
relaxed in
C++0x, the objective of this proposal is to allow the designer to
force a struct
to be POD and to allow the compiler to output errors if the
requirement is
violated.

As with any proposal for language change there comes the issue of
syntax or
keyword usage. This proposal follows the hallowed tradition of piling
yet
another meaning onto the 'static' keyword. To mark a struct as POD one
adds the
static keyword after the struct (or class) keyword:

struct static Foo { ... };

Once marked as POD, any construct that would make it impossible
for the
struct to be POD MUST be flagged as an error by the compiler:

class Foo {
public:
virtual int f() {}
};

struct static Bar : public Foo { ... }; // error Bar cannot
contain
// virtual functions

struct static Baz {
int x;
Foo foo; // error, POD structs cannot contain non-POD elements
};

struct static Boo { ... };

class Goo : public Boo {
public:
virtual int f() {} // this is legal, Goo is not POD
};

That's it in a nutshell. A few anticipated concerns are addressed
below:

Does C++ need this?

Do we need anything? Seriously, every version of C++'s language
specification spent a section or two describing what POD is and how to
achieve
it for backward compatibility with C and system calls. Having a way
for the
compiler to know what MUST be POD and tell you when you have caused a
struct to
exit the realm of POD must be a useful concept. Frankly, I'm surprised
it
doesn't already exist.

Couldn't attributes be used instead of overloading static yet again?

My understanding of attributes is that they are helpers to the
compiler. The
whole point of adding POD requirements to struct is as a help to the
library
developer. So while it could be done with attributes (as could default
and
deleted constructors, for example), attributes speak to the compiler.
Here, the
library designer is speaking to the library user.

Should POD status affect name-mangling?

This is not a lang-spec issue really. It would be nice since it
would ensure
the POD status of the struct across separate compilations. It would
also break
existing ABIs however that should not be an issue since moving from C+
+03 to
C++0x will also break existing ABIs I suspect.

Does this impact compatibility with C?

I suspect that if this proposal were accepted as part of C++ a lot
of existing
headers would be modified using a #define that is defined as empty
when the
compiler is in C mode and is defined as static when in C++ mode:

#ifdef __CPLUSPLUS
#define __POD__ static
#else
#define __POD__
#endif

struct __POD__ FILELAYOUT { ... };


Thanks for listening. I'll now stand back and see where I've gone
astray. :)

Joe Mucchiello
 
A

Alan Woodland

jmucchiello said:
I posted this to comp.std.c++ last week and it never showed up so I'll
post it here to see if there's any interest. Sorry if that's against
the rules but I don't know where a FAQ might be.
http://www.parashift.com/c++-faq-lite/ (Doesn't mention this I don't think?)

A few quick comments:
Hi, I have a proposal for a language addition. I realize it is far
too late
for this idea in C++0x but I think it would be a good addition to the
language.

My proposal is to make it possible to explicitly mark a struct (or
class) as
plain-old-data (POD). Currently, the language specification states the
rules for
determining IF a struct (or class) is POD. While these rules were
relaxed in
C++0x, the objective of this proposal is to allow the designer to
force a struct
to be POD and to allow the compiler to output errors if the
requirement is
violated.

As with any proposal for language change there comes the issue of
syntax or
keyword usage. This proposal follows the hallowed tradition of piling
yet
another meaning onto the 'static' keyword. To mark a struct as POD one
adds the
static keyword after the struct (or class) keyword:

struct static Foo { ... };

I'm not sure I like the idea of writing:

static struct static Foo { ... } inst;

It's almost as bad as trying to explain to someone what

int const * const

and permutations thereof actually mean!
Once marked as POD, any construct that would make it impossible
for the
struct to be POD MUST be flagged as an error by the compiler:

class Foo {
public:
virtual int f() {}
};

struct static Bar : public Foo { ... }; // error Bar cannot
contain
// virtual functions

struct static Baz {
int x;
Foo foo; // error, POD structs cannot contain non-POD elements
};

struct static Boo { ... };

class Goo : public Boo {
public:
virtual int f() {} // this is legal, Goo is not POD
};

That's it in a nutshell. A few anticipated concerns are addressed
below:

Does C++ need this?

Do we need anything? Seriously, every version of C++'s language
specification spent a section or two describing what POD is and how to
achieve
it for backward compatibility with C and system calls. Having a way
for the
compiler to know what MUST be POD and tell you when you have caused a
struct to
exit the realm of POD must be a useful concept. Frankly, I'm surprised
it
doesn't already exist.

Couldn't attributes be used instead of overloading static yet again?

My understanding of attributes is that they are helpers to the
compiler. The
whole point of adding POD requirements to struct is as a help to the
library
developer. So while it could be done with attributes (as could default
and
deleted constructors, for example), attributes speak to the compiler.
Here, the
library designer is speaking to the library user.

Should POD status affect name-mangling?

This is not a lang-spec issue really. It would be nice since it
would ensure
the POD status of the struct across separate compilations. It would
also break
existing ABIs however that should not be an issue since moving from C+
+03 to
C++0x will also break existing ABIs I suspect.

Does this impact compatibility with C?

I suspect that if this proposal were accepted as part of C++ a lot
of existing
headers would be modified using a #define that is defined as empty
when the
compiler is in C mode and is defined as static when in C++ mode:

#ifdef __CPLUSPLUS
#define __POD__ static
#else
#define __POD__
#endif

struct __POD__ FILELAYOUT { ... };


Thanks for listening. I'll now stand back and see where I've gone
astray. :)

How do you propose this should interact with templates? Surely this
would be the most useful area for it. I.e. the template parameter
must/musn't be a POD would be useful, but is totally overlooked by your
suggestion as it stands.

If concepts isn't dead (C++2X? ;) perhaps?) then isn't this just one
area which would be covered by concepts and thus completely redundant?

Alan
 
D

Daniel Pitts

jmucchiello said:
I posted this to comp.std.c++ last week and it never showed up so I'll
post it here to see if there's any interest. Sorry if that's against
the rules but I don't know where a FAQ might be.
-------
Hi, I have a proposal for a language addition. I realize it is far
too late
for this idea in C++0x but I think it would be a good addition to the
language.

My proposal is to make it possible to explicitly mark a struct (or
class) as
plain-old-data (POD). Currently, the language specification states the
rules for
determining IF a struct (or class) is POD. While these rules were
relaxed in
C++0x, the objective of this proposal is to allow the designer to
force a struct
to be POD and to allow the compiler to output errors if the
requirement is
Perhaps instead a declaration, make it an assertion.

I don't have a lot of practice with metaprogramming in C++, but I could
imagine there is some sort of test one couple perform that indicates
whether a particular datatype is POD or not. That way you could do
something like:

struct somepod {...};

ASSERT_POD(somepod);

and more importantly:

template<typename foo>
void doSomethingWithPod(foo f) {
ASSERT_POD(somepod);
}
 
A

Alan Woodland

Daniel said:
Perhaps instead a declaration, make it an assertion.

I don't have a lot of practice with metaprogramming in C++, but I could
imagine there is some sort of test one couple perform that indicates
whether a particular datatype is POD or not. That way you could do
something like:

struct somepod {...};

ASSERT_POD(somepod);

and more importantly:

template<typename foo>
void doSomethingWithPod(foo f) {
ASSERT_POD(somepod);
}
Here we go:

template <typename T>
class pod_asserter {
public:
enum {is_pod=1};
private:
typedef union {
T inst;
} pod_asserter_t;
static pod_asserter_t test;
};

#define ASSERT_POD(x) ((void)pod_asserter< x >::is_pod)

struct foo {
int a;
};

struct bar {
virtual ~bar() {}
};

int main() {

ASSERT_POD(foo);
ASSERT_POD(int);
ASSERT_POD(float);
ASSERT_POD(bar);

return 0;
}

Of course that won't work with C++0x though! The error message isn't
great either, but I think that could be improved.

Alan
 
B

Balog Pal

jmucchiello said:
I posted this to comp.std.c++ last week and it never showed up so I'll
post it here to see if there's any interest. Sorry if that's against
the rules but I don't know where a FAQ might be.
-------
Hi, I have a proposal for a language addition. I realize it is far
too late
for this idea in C++0x but I think it would be a good addition to the
language.

My proposal is to make it possible to explicitly mark a struct (or
class) as
plain-old-data (POD).
....

I plan a similar thing, more elaborated control on the layout as just POD.
In a few words I'd like add two attributes, 'free-layout' and
'standard-layout' (note: in C++0x that is the term used for what you refer
as POD...)

The second would force a strict POD-compatible layout if it is possible (
removing the fiddling-license of the implementation wrt private sections,
etc...) and make the program ill-formed if it is not possible (i.e. having
virtuals).

The first would go the other direction, allowing to ignore the current
laying-out rules, like 'increasing order within the same access section' and
'distinct address for every member' -- IOW allowing free reordering of the
data members and use zero-size for empty members.
And a good compiler would have a switch to make 'free-layout' the default
for everything not wearing the other attribute.

I think the new 'attribute' facility is fit to handle the case in a
convenient way, and is similar to how similar stuff is already controlled in
the practice.
 
G

Greg Herlihy

Daniel Pitts wrote:
Here we go:

template <typename T>
class pod_asserter {
public:
        enum {is_pod=1};
private:
        typedef union {
                T inst;
        } pod_asserter_t;
        static pod_asserter_t test;

};

#define ASSERT_POD(x) ((void)pod_asserter< x >::is_pod)

struct foo {
   int a;

};

struct bar {
   virtual ~bar() {}

};

int main() {

   ASSERT_POD(foo);
   ASSERT_POD(int);
   ASSERT_POD(float);
   ASSERT_POD(bar);

   return 0;

}

For C++0x, just use this test:

#include <type_traits>

static_assert(std::is_pod<x>::value, "type is not a pod");

replacing "x" with the type to be tested.

Greg
 
J

jmucchiello

Perhaps instead a declaration, make it an assertion.

That removes all ability for the compiler to optimize around it. Also
there is nothing stopping someone from screwing up the meta-
programming object and declaring a non-POD POD. I also think the
ability to export the POD status of struct to the name-mangling is
helpful for large projects where you don't want someone coming along
and adding a virtual function to an internal used struct. The linker
would point out that the POD and non-POD versions of the same struct
are not the same type.
 
A

Alan Woodland

jmucchiello said:
That removes all ability for the compiler to optimize around it. Also
That's not true at all - it's pretty straightforward for a compiler to
tell if something is a POD or not, and act sensibly and I'd be willing
to bet that most do where possible.
there is nothing stopping someone from screwing up the meta-
programming object and declaring a non-POD POD. I also think the
Yes there is, the ASSERT_POD example I provided does exactly that, using
the current language, and apparently this will be supported without any
trickery at all in C++0x.
ability to export the POD status of struct to the name-mangling is
helpful for large projects where you don't want someone coming along
and adding a virtual function to an internal used struct. The linker
would point out that the POD and non-POD versions of the same struct
are not the same type.
Relying on the name mangling scheme explicitly for doing anything seems
like a bad idea. I fail to see how any proposal encouraging people to
assume specific things about name-mangling schemes, which are
implementation defined can be a good thing.

You also talked about C compatibility for PODs, but this:

template <typename T>
struct foo {
T bar;
};

is a POD, yet not 'C' compatible in respect, and doesn't even result in
any symbols in the output anyway to inspect the 'POD status' of it as
you'd like us to do.

As far as I know most implementations don't store any type info of
instances in the symbols they export, e.g:

foo<int> inst;

results in:
ajw05@pc2ajw05:~ > nm test.o


0000000000000000 B inst

on my platform. What would you expect to change there if I accidentally
made inst not a POD? Currently I can't even tell if it's an int, a POD
or a non-POD by inspecting the binary.

It seems like the useful parts of this proposal (being sure if any type
is POD or not) are already feasible, and being improved in upcoming
standards apparently. The other parts seem to have dubious usefulness
and technical merits.

Alan
 
J

jmucchiello

You also talked about C compatibility for PODs, but this:

template <typename T>
struct foo {
        T bar;

};

is a POD, yet not 'C' compatible in respect, and doesn't even result in
  any symbols in the output anyway to inspect the 'POD status' of it as
you'd like us to do.

No, it is not a POD. T can be a non-POD type and that would make foo
non-POD. This example is exactly what my proposal is for. In my
proposal, you would say:

template <typename T>
struct static foo {
T bar;
};

class C {
public:
virtual ~C() {}
};

foo<C> aFoo; // compiler error

How would you get the same functionality using a static assert?

I brought up C compatibility for stuff like operating system structs.
That has nothing to do with whether or not valid C++ POD structs are
the valid C structs.

#ifdef __CPP__
#define __POD__ static
#else
#define __POD__
#endif

struct __POD__ FILETIME {
time_t created;
time_t modified;
time_t accessed;
#ifdef __CPP__
FILETIME(time_t c, time_t m, time_t a) : created(c), modified(m),
accessed(a) {}
FILETIME(time_t t = 0) : created(t), modified(t), accessed(t) {}
#endif
};
As far as I know most implementations don't store any type info of
instances in the symbols they export, e.g:

foo<int> inst;

Of course not, there's nothing about that in the spec: try this and
watch how much type info is generated. I specifically talked about
name mangling, not global data.

foo<int> func(foo<int> a) {
return 0;
}
 
A

Alan Woodland

jmucchiello said:
No, it is not a POD. T can be a non-POD type and that would make foo
non-POD. This example is exactly what my proposal is for. In my
proposal, you would say:

template <typename T>
struct static foo {
T bar;
};

class C {
public:
virtual ~C() {}
};

foo<C> aFoo; // compiler error

How would you get the same functionality using a static assert?
The fact that foo<T> is/isn't a POD isn't what actually matters when you
declare/define foo though. It's where foo<T> gets used that it matters.
It's not an error to pass some T that makes foo non-POD, unless you
later hand foo off to something that assumes foo<T> is always POD.

If foo assumes that T itself is POD then it's easy enough to modify
ASSERT_POD to work inside of foo's definition.

Where it really matters that foo<T> is a POD would be the place where
you do something that assumes it is a POD (e.g. memcpy or whatever), and
that's the place I'd be looking to put the ASSERT_POD call. An
ASSERT_POD in some function that calls memcpy serves as documentation to
a reader, and enforces it through the compiler. In fact if you didn't
put ASSERT_POD in places where you actually did things that assumed it
was POD you'd still be open to breakages later on, even with your
proposed way of doing things.

e.g.:

template <typename T>
void super_optimised_pod_routine(const T& bar) {
ASSERT_POD(T);
// do some clever fast things here
}

Under your proposal there is no way to say T must be a POD here, which
is by far the most useful scenario for POD testing.

I fail to see any strong arguments for benefits of what you propose that
can't already be covered (arguably better) by checking PODness where it
really counts.

I'd be more enthusiastic about a proposal for allowing you to write:
template <POD T>
except for the fact it's already possible to achieve this functionality
as I outlined.
Of course not, there's nothing about that in the spec: try this and
watch how much type info is generated. I specifically talked about
name mangling, not global data.

foo<int> func(foo<int> a) {
return 0;
}
It's completely implementation defined what I see from that. There's no
reason why your implementation can't write POD in big letters there
already if whoever made your implementation thought it mattered. It
seems somewhat bizarre to leave mangling completely open-ended yet add
one small caveat requiring implementations to mention if the arguments
and return types are POD or not. For what's required of an
implementation right now the mangling could be done based on a MD5 hash!

Alan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,186
Members
46,740
Latest member
JudsonFrie

Latest Threads

Top