Boost logo

Boost :

From: Douglas Gregor (gregod_at_[hidden])
Date: 2001-08-22 10:44:54


On Wednesday 22 August 2001 01:43, you wrote:
> Douglas Gregor wrote:
> > print_string() and print_int() are function objects that can be invoked
> > given an instance of std::string or int, respectively.
>
> Ah, I see!
>
> > The parsing of the construct:
> >
> > variant_switch(v)
> > .on<std::string>(print_string())
> > .on<int>(print_int())
> > .on_default(print_unknown());
> >
> > variant_switch(v) returns an object of type variant_switch_stmt that
> > contains a reference to "v".
[snip]
> >
> > I'm not clear that it is even a fix, per se. I think that it is entirely
> > possible to emulate variants in C++ using templates. If so, I don't
> > believe there is any use in adding a redundant feature to the language.
>
> If you can eliminate all possibility of failure
> at run time. I think this is possible too, with some
> extra template trickery.

This is a similar problem to that of the list initialization trick, i.e.,
v = 1, 2, 3, 4, 5;

if v is a container of length six, can we detect at compile-time that this is
an incomplete initialization? I personally haven't seen a solution to this
problem, and I've spent a while trying to find one :(. Associativity is the
problem, here: v = 1 must be evaluated first (because we can't redefine
operator,(int, int)), but we really need operator= to be done last so we have
a chance to do more static checking.

My favorite solution would be to use the fact that a user-defined operator
void() will never be invoked, so a core language extension could call a
user-defined operator void() at the end of a full expression before
destruction of temporaries. Then the above list initialization statement
would merely store up the entire expression v = 1, 2, 3, 4, 5; in an object.
The object (the result of the overall expression) would have is operator
void() invoked at the end of the statement. This call would fail to compile
if no enough elements were specified, or would perform the operation if the
correct number of elements is in the list.

Back on topic... It is possible to rearrange the syntax of the variant_switch
a little bit. We could use vswitch and vcase in a manner similar to C's
switch/case:

  vswitch(v) (
      vcase<T1>(action1)
    | vcase<T2>(action2)
    | vcase<T3>(action3)
  );

  vswitch(v) returns a function object that can perform the switch-on-tag.
vcase is a function at namespace scope. Since the set of vcase's is an
argument to the function object returned by vswitch, we have all of the vcase
statements gathered before we try to do the switch, so static checking is
possible.

C switch can be emulated in the same way with T1, T2, T3 being integral
constant expressions.

[line split]
> [Of course, the inheritance
> trick introduces a memory management problem which in
> principle is independent of the semantic one: the same
> problem exists in ML and is 'solved' by GC, so to be fair,
> one should ignore that since one expects to manage memory
> in C++ manually]

Inheritance? That doesn't play into this design at all, except as one
possible way to create a variant class template (vswitch/vcase need not be
dependent on any specific variant type).

        Doug


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