|
Boost : |
From: Itay Maman (itay_maman_at_[hidden])
Date: 2002-06-28 05:03:15
It seems that the variant issue is very popular these days ... :)
The last couple of weeks I've been implementing a variant class
based on the ideas (which were, in large part, contributed by Doug
Gregor) discussed here in "Proposal --- a type safe union"
The main advantage of this variant implementation is the flexibility of
its visitor mechanism, which accepts 'standard' function objects. Having
this flexibility at hand, the implementation of other key-features (e.g:
recursive types) became fairly simple.
The source code (with two short programgs) is available at
http://groups.yahoo.com/group/boost/files/variant_b.tar.gz
Key points
----------
- Supports construction and assignment from any of the types that the
variant can hold.
- Uses overload resolution rules for construction, assignment, and
visitation.
- Can be visited by any function object. Performs compile-time check to
make sure the given function object can accept any of the possible types.
- Supports construction/assignment from variants with a different list
of types.
- Supports holding of incomplete types.
- Recursive types are allowed via incomplete types.
- (Exception safe) value semantics.
- Uses stack-based storage technique.
- Variant to variant assignment is (internally) carried out thru
visitation.
- Does not use dynamic_cast's nor typeid()'s
Comments
--------
* This implementation can use either mpl::list or Loki::Typelist for
manipulating types, determined by the USE_LOKI_SEQ preprocessor symbol.
The macros TYPE_SEQ_1 .. TYPE_SEQ_10 are used to instantiate the proper
type-list.
* I tried to work with mpl but the compilation times were painfully
slow. I did read the other day, that the latest mpl code does solve this
problem, but didn't get to check it out, yet.
* The code hasn't been fully Boostified. It was tested on GCC 3.0.4, but
porting it to MSVC shouldn't be too difficult.
Feedback is welcome.
-Itay
Usage
-----
#include <iostream>
#include <boost/variant.hpp>
using boost::Variant;
using boost::Incomplete;
using std::cout;
using std::endl;
struct Add;
struct Sub;
typedef Variant<TYPE_SEQ_3(int, Incomplete<Add>, Incomplete<Sub> ) > Expr;
struct Add
{
Add() { }
Add(const Expr& l, const Expr& r) : lhs_(l), rhs_(r) { }
Add(const Add& other) : lhs_(other.lhs_), rhs_(other.rhs_) { }
Expr lhs_;
Expr rhs_;
};
struct Sub
{
Sub() { }
Sub(const Expr& l, const Expr& r) : lhs_(l), rhs_(r) { }
Sub(const Sub& other) : lhs_(other.lhs_), rhs_(other.rhs_) { }
Expr lhs_;
Expr rhs_;
};
struct Calculator
{
Calculator() : result_(0) { }
void operator()(Add& x) const
{
result_ = x.lhs_(Calculator()).result_ +
x.rhs_(Calculator()).result_;
}
void operator()(Sub& x) const
{
result_ = x.lhs_(Calculator()).result_ -
x.rhs_(Calculator()).result_;
}
void operator()(Expr& x) const
{
result_ = x(Calculator()).result_;
}
void operator()(int x) const
{
result_ = x;
}
mutable int result_;
}; // Calculator
int main(int argc, char *argv[])
{
argc = argc;
argv = argv;
int n = 13;
// e1: n + (40+2)-(10+14) = n+28
Expr e1( Add(n, Sub(Add(40,2),Add(10,4))) );
//Evaluate expression
int res = e1(Calculator()).result_;
cout << "result = " << res << endl;
assert(res == n + 28);
return 0;
}
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk