Boost logo

Boost :

From: Alexander Nasonov (alnsn-mycop_at_[hidden])
Date: 2003-09-01 06:01:51


David Abrahams wrote:

> "Dirk Schreib" <Dirk.Schreib_at_[hidden]> writes:
>
>> I would like a variant to be LessThanComparable if all
>> BoundedTypes are LessThanComparable.
>>
>> 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 ).
>>
>> I assume that the resulting variant class will be StrictWeaklyComparable
>> if all
>> BoundedTypes are StrictWeaklyComparable.
>
> Sounds like maybe you want dynamic_any. Have you looked at Alexander
> Nasonov's work?

I would like to emphasize one difference with variant library. User should
_add_ less operation to the list of supported operations to enable
operator<. This operator isn't enabled by default. This protects from
undesirable effects because if the user added less I can assume that she
knows what she's doing. But the problem of different order is still
persist.

I think we should coordinate our work on variant and dynamic_any library.
The discussed problem is one point where coordination is needed.

Both libraries work with some set of types by (i) storing value of one
selected type and (ii) calling some operation for stored value. This is
done with some differences, though. In assumption that typedefs for variant
and dynamic_any fixed I can say that:
1. variant operates with _fixed_ set of stored types but with _open_ set of
supported operations (through static_visitor)
2. dynamic_any has _open_ set of stored type but _fixed_ set of supported
operations

There is also some differences in operation support. Variant's operation
looks like:

struct print : static_visitor<void>
{
  std::ostream& out_;
  print(std::ostream& out) : out_(out) {}

  template<class T>
  void operator()(const T& value) const
  {
    out_ << value;
  }
};

while dynamic_any operation looks like:

struct print : function<print, void (std::ostream&, const anyT&)>
{
  template<class T>
  void call(std::ostream& out, const T& value) const
  {
    out << value;
  }
};

On one hand, variant uses operator() which is good for "anonymous"
operations (obviously, it's not possible for dynamic_any):

variant<int, char> v(0);

// "anonymous" function is ok
apply_visitor(v, std::cout << _1);

 // error, attempt to call std::cout << v
for_each(&v, &v + 1, std::cout << _1);

// ok
for_each(&v, &v + 1, print(std::cout));

On the other hand, dynamic_any has better support for std algorithms,
lambda, bind, etc (well, in variant case it's also possible by binding
apply_visitor):

dynamic_any::any<mpl::list<print> > a(0);

// ok, direct call
print()(std::cout, a);

// ok if result of print doesn't contain anyT (void doesn't)
// otherwise, bind<R> is required
for_each(&a, &a + 1, bind(print(), std::cout, _1));

Other advantage of dynamic_any is a possibility to mix "normal" arguments
and anyT-based. Due to nature of dynamic_any it's not possible to call the
operation containing two or more anyT-based arguments for arbitrary
arguments. Call can be made only if all "any" arguments hold same type or
are derived publicly from one type T stored by one "any" argument.
However, "less" works fine with arbitrary types because I added
call_ex/no_call mechanism to the library.
In variant the set of stored types is fixed and all combinations can be
considered (be careful, it may cause combinatorial explosion):

struct plus : variant::function<plus, variantT (variantT, variantT)>
{
  template<class T1, class T2>
  typeof(v1 + v2) call(T1 v1, T2 v2) const
  {
    // Note that T1 and T2 are in general
    // different (in opposite to dynamic_any)
    return v1 + v2;
  }

  template<class T2>
  std::string call(std::string v1, T2 v2) const
  {
    return v1 + lexical_cast<std::string>(v2);
  }

  template<class T1>
  std::string call(T1 v1, std::string v2) const
  {
    return lexical_cast<std::string>(v1) + v2;
  }

  // ...
};

variant<std::string,int,char> s("s");
variant<std::string,int,char> i(0);

variant<std::string,int,char> s0 = plus()(s, i);
// s2 == std::string("s0")

--
Alexander Nasonov
Remove minus and all between minus and at from my e-mail for timely response

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