Boost logo

Boost :

From: Eric Friedman (ebf_at_[hidden])
Date: 2003-08-30 19:43:38


Dirk Schreib wrote:
> I would like a variant to be LessThanComparable if all
> BoundedTypes are LessThanComparable.

I've actually been working on this on and off for some time. I have not
committed anything to CVS though because I have found that defining
relational operators for variant that are always meaningful is unfortunately
tricky, and perhaps impossible (see below).

> 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.

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<
      return lhs.which() < rhs.which()

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.

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> >

I'd appreciate feedback.


P.S. The issue of equality comparison between variants is a bit more
straightforward. However, we still have the following potentially confusing

  typedef variant<int, double> var;
  bool result3 = (int(3) == double(3.0)); // true
  bool result4 = (var(3) == var(3.0)); // false

Thus, perhaps a boost::variant_equal comparison function is also in order.

Boost list run by bdawes at, gregod at, cpdaniel at, john at