Boost logo

Boost :

From: Dirk Schreib (Dirk.Schreib_at_[hidden])
Date: 2003-08-31 03:58:28


Hello Eric,

"Eric Friedman" <ebf_at_[hidden]> wrote
> Dirk Schreib wrote:
> > [...]
> > In this example
> >
> > typedef boost::variant<T1, T2, ..., TN> V;
> > V v1 = T1( x );
> > V v2 = T2( y );
> > V v3 = T1( z );
> >
> > v1 < v2 should always be true. And v1 < v3 should be the same as T1( x )
<
> > T1( z ).
>
> For starters, I agree that v1 < v3 should be the same as x < y.

Ok.

> I'm not so sure about v1 < v2, though. I'm inferring that you believe that
> operator< should be implemented as follows:
>
> template <typename T1, ..., typename TN>
> bool operator<(
> const variant<T1,...,TN>& lhs,
> , const variant<T1,...,TN>& rhs
> )
> {
> if (lhs.which() == rhs.which())
> ... // compare using underlying operator<
> else
> return lhs.which() < rhs.which()
> }

This is exactly what I want.

> While this certainly solves the problem of storing variants in associative
> containers by establishing an ordering, the ordering is rather arbitrary
and
> potentially confusing. Consider the following:
>
> typedef variant<int, double> var;
> bool result1 = int(3) < double(2.0); // false
> bool result2 = var(3) < var(2.0); // true
>
> On first glance, IMO most users would expect result1 == result2. With your
> ordering scheme, this would be untrue. Unfortunately, I do not believe the
> problem is specific to your ordering scheme.

Trying to establish an ordering between unrelated types where each type does
not
fall into it's own category is very difficult. My ordering scheme is very
easy and
simple because you never have to compare two different types.
Alternative solution would be to use

  typedef variant<T1, T2> var;
  bool operator<( T1 const& lhs, T2 const& rhs);

which usually does not exist. Even if it is possible to compare two
different types
with integral promotion or user defined conversion operators it will impose
problems on asymetry and transitivity.

  typedef variant<double, std::string, int> var;
  bool result1 = var(3.0) < var(2); // false or true?
  bool result2 = var(3.0) < var("2.5"); // false or true?
  bool result3 = var("2.5") < var(2); // false or true?

  // if (result2 && result3) ==> result1 = true.

> Ultimately, I do not believe any ordering scheme will provide meaningful,
> straightforward semantics. Assuming I am correct, I propose that the
variant
> library offer your ordering scheme -- but only as an explicit comparison
> function, calling it variant_less. This would allow, for instance:
>
> std::set< my_variant, boost::variant_less<my_variant> >

The default comparison operator for std::set<T> is std::less<T>
(which just uses operator<() ) and I would like this to work with
variant too. If there are no "meaningful, straightforward semantics"
the user will not put a variant into a set. If "my" ordering scheme
is the only one offered by variant, it can be the default too.

> P.S. The issue of equality comparison between variants is a bit more
> straightforward. However, we still have the following potentially
confusing
> situation:
>
> typedef variant<int, double> var;
> bool result3 = (int(3) == double(3.0)); // true
> bool result4 = (var(3) == var(3.0)); // false

I need exactly this behaviour...
> Thus, perhaps a boost::variant_equal comparison function is also in order.

...and don't have a need for this ;-)

Dirk


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