Boost logo

Boost :

From: Paul Mensonides (pmenso57_at_[hidden])
Date: 2004-11-15 16:34:37


> -----Original Message-----
> From: boost-bounces_at_[hidden]
> [mailto:boost-bounces_at_[hidden]] On Behalf Of Alexander Nasonov

> > Doing so just propagates a bad design (which is what it appears to
> > be). What exactly are you doing that requires this
> behavior, because
> > I guarantee there is a better, more structured, way to do it that
> > doesn't involve ill-formed constructs or invalid sequences.
>
> Paul,
> I understand your worry and I'm not going to use pp seq
> interface to extract arguments tuple, I'm just trying to
> understand whether it's possible to:
>
> 1. extract x from (x)(a,b,c)
> 2. remove (x) from (x)(a,b,c)

Yes, it is certainly possible. The simplest way, minus workarounds, is:

#define CAT(a, b) PRIMITIVE_CAT(a, b)
#define PRIMITIVE_CAT(a, b) a ## b

#define SPLIT(i, im) PRIMITIVE_CAT(SPLIT_, i)(im)
#define SPLIT_0(a, b) a
#define SPLIT_1(a, b) b

#define EXTRACT(data) SPLIT(0, EXTRACT_I data)
#define EXTRACT_I(x) x,

#define REMOVE(data) SPLIT(1, EXTRACT_I data)

> I don't think my design is really bad, if, after all, it can
> be expressed in valid C++. Compare:

My only concern is that you are currently using sequence primitives on data
structures that aren't sequences. They happen to work in this case. It is
roughly equivalent to calling an STL algorithm with an iterator range where the
end iterator cannot be reached from the begin iterator. In some cases it may
well work, but there are no guarantees. With the preprocessor specifically, it
is an undetectable failure to achieve a precondition. Reliance on undocumented
and unguaranteed behavior *is* bad design.

> BOOST_TRACE_MEM_FUN( (foo)((buf)(len)) );
> BOOST_TRACE_MEM_FUN( (foo)(2, (buf,len)) );
> // These two are only for pp funs ;-)
>
> BOOST_TRACE_MEM_FUN( foo, (buf, len) );
> // Comma is unnatural and looks like a typo
>
> BOOST_TRACE_MEM_FUN( (foo)(buf, len) );
> // Valid C++ call syntax. Brackets around foo can be explained in
> // docs.

Personally, I think that TRACE_MEM_FUN(foo, (buf, len)) is the most natural as
well as the easiest to port, unless you need (at some point) access to the
elements inside (buf, len), in which case I'd prefer TRACE_MEM_FUN(foo,
(buf)(len)).

You have two separate pieces of data, which can be supplied in multiple ways--as
two distinct parameters or as a data structure. If it is passed as a data
structure, it is arguably better not to use a "custom" data structure format
just for slightly prettier syntax (IYO). If you use two separate parameters, it
avoids the need to extract or remove anything. If you are going to use a data
structure, I'd go with (foo)((buf)(len)) or (foo)((buf, len)). I'd choose the
first if you ever are going to need to do anything with the two (or more)
elements.

Later, when variadics are generally available in C++, you can make this
interface significantly better. Until then, however, nothing is going to be
syntactically "perfect".

Regards,
Paul Mensonides


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk