The Phantom Menace Was Not a Very Good Movie

I own all of the Star Wars DVDs except for one – The Phantom Menace. Even the weakest of the others have a certain charm, but TPM was stupid through and through. Even the title is stupid! I have yet to work out exactly what the titular menace actually was. Although the story includes several menaces, none of them seem particularly phantomastical. Unless the menace was supposed to be Palpatine’s amazingly convoluted plan, but that plot point doesn’t really bear fruit until the second film.

Anyway, I haven’t given The Phantom Menace much thought since it first came out but this guy certainly has:




Part 1
Part 2
Part 3
Part 4
Part 5
Part 6
Part 7

Even if you ignore the affectations of the reviewer, he has some pretty insightful points about how TPM fails as a movie.

The C++ Boost Libraries Part 6 – boost::any

In C++ if you have a variable that you say is of type “Person” (for instance), you can be fairly certain (more or less) that it always actually contains a Person (or perhaps a subclass of Person. If you have a container of Persons, then you know (more or less) that every member is also a Person (or a subclass).

This is all very good, prevents a lot of runtime errors, and generally makes C++ a great language if you care about correctness. But sometimes, very rarely, you actually want to store a whole bunch of messy, unrelated types in a container without trying to ram them into some sort of class hierarchy. Parsers are a good example of this. It is often convenient just to chuck tokens of various types into a data structure for later processing without worrying too much about the specific type (string, int, float, etc).

boost::any is a small class that can hold values from almost any type, designed for just such messy applications. Using boost::any is very simple:

1
2
boost::any a1 = std::string("Moose");
boost::any a2 = 6;

Of course, getting the values back again is a little harder.

1
2
3
4
5
6
7
8
9
try
{
	std::string v1 = boost::any_cast< std::string >(a1); // this works, a1 is a string
	std::string v2 = boost::any_cast< std::string >(a2); // nope, will throw an exception at runtime
}
catch ( const boost::bad_any_cast& e )
{
	// tried to any_cast into something that wouldn't go
}

Of course, you can query a boost::any for the typeid of the stored object. Just don’t do it when Scott Meyers is in the vicinity.

1
2
3
4
5
std::string v;
if ( a1.type() == typeid(std::string) )
{
	v = boost::any_cast< std::string >( a1 ); // this should never throw, since we checked first
}

A single boost::any is perhaps not that useful, but a container of them can store almost anything we want:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
typedef std::vector< boost::any > AnyVector;
AnyVector values;
 
values.push_back( 5 );
values.push_back( std::string("Hello") );
values.push_back( 5.3 );
 
try 
{
	for ( AnyVector::const_iterator p = values.begin();
			p != values.end();
			++p )
	{
		if ( p->type() == typeid(int) )
			cout << "Int = " << any_cast<int>(*p) << endl;
		else if ( p->type() == typeid(std::string) )
			cout << "String = " << any_cast<string>(*p) << endl;
		else 
		{
			cout << "Unhandled type: " << p->type().name() << endl;
		}
	}
} 
catch ( const boost::bad_any_cast &e )
{
	cout << "Bad any_cast<>" << e.what() << endl;
}

Any type that you put into a boost::any must be copy constructable (the any makes a copy, not a reference). You also have to make sure that its destructor doesn’t throw (but of course you do that anyway!)

Although I wouldn’t recommend boost::any for everyday use, it does come into its own when the only alternative is a huge class structure or (even worse) void *s.