Clark Cox wrote:
In article <c0**********@a rcturus.ciril.f r>,
Emmanuel Thome <Em************ *****@loria.fr> wrote:Extending the language, say via a keyword, to include ``ghost''
classes (by lack of a better name), which really occupy zero storage
when they are empty and present as members of anything would be, IMHO,
a very valuable addition.
Why would it be valuable? What possible benefit could this provide?
Valuable for efficiency. Benefits for code simplicity, compared to
other (existing) solutions. The explanation below is lengthy, sorry.
As explained in
http://www.cantrip.org/emptyopt.html, the nonzero
padding leads to some bloat. For efficiency reasons, ways to avoid it
are desired.
Using a template to make the possibly empty class a base class of some
non-empty member is a way to achieve this. boost::compress ed_pair does
so. It is successful in many cases, but restrictions do exist (namely,
you've got to articulate your possibly empty classes around some
non-empty member).
A working code context could be somewhat long and not very
illuminating, I'll only give a sketch (which, unfortunately, does grow
to some length). Consider first the following:
/* objective: behave like an int, without being an int */
template<class T, T v> class fake {
public:
fake() {};
fake(T w) {};
fake(const fake&) {};
~fake() {};
const fake& operator=(const fake&) { return *this;};
T value() { return v; };
};
template<class T, T v> int int_value(fake< T,v> a) { return a.value(); }
int int_value(int a) { return a; }
The idea is to have fake<int, 3> look like an int in some aspects
(really few here :-)), but really be 3 always. Attempts to assign
anything else than 3 to it may be tracked, but we do not want to
forbid such assignments altogether.
As it is, an object of type fake<int,3> occupies nonzero storage, but
that doesn't disturb me too much yet. I'm ok with wasting a couple of
bytes on the stack, not too often.
Now say we've got a handful of properties, which may be either
variable (int) or fixed (fake<int, 3>). These properties are put
together in a template:
template<class U, class Ta, class Tb> class qualified_data {
U raw_data;
Ta p1,p2,p3;// some of type Ta
Tb p4,p5,p6;// some of type Tb
/* lots of interface stuff. */
};
of course we want instantiations of qualified_data to be as small as
possible. As written above, bloat will be significant, and arrays
created from qualified_data will be unsatisfyingly large. A solution
could be to use compressed_pair (abbreviated cp), with the following
statement.
cp<Ta,cp<Ta,cp< Ta,cp<Tb,cp<Tb, cp<Tb, U> > > > > > props;
and then, have accessors for the different fields:
const Ta& p1() const { return props.first(); };
...
const Ta& p5() const { return
props.second(). second().second ().second().fir st(); };
Even if the above statement can be easily trimmed down by some
classical template tricks, the code obtained is error-prone. The
first, naive syntax above makes life easier. Agreed, this is making
life easier for the developer rather than the user, which is a
debatable objective.
If really empty classes were available, the first, much lighter,
syntax would be just as efficient as the first one.
Now, maybe nobody's convinced. I don't want to bother people with the
innards of the project I'm working on. Furthermore, it does turn out
that restating my original problem this way suggests me adding some
syntactic sugar around the cp<cp<cp<...>>> solution above so that I
can get it to be less error-prone. Maybe it'll work out, I'll see. I'm
thinking of statements such as this:
#define TAG_FIELD_1 0x12340001 // and so on...
field_list <
field<Ta, TAG_FIELD_1,
/* ... */
field<Tb, TAG_FIELD_6,
void> > > > > > > many_fields;
const Ta& p5() const { return many_fields.acc ess(TAG_FIELD_5 ); };
I honestly believe that this does not discard my argument about the
interest of really empty classes. So much trickery is exhausting.
E.