I have used boost::exception for a while now and I really like inserting arbitrary data into an exception.
I do this in addition to specific exception types, e.g.
#define MY_THROW(x) \
BOOST_THROW_EXCEPTION(x << errinfo_thread_id(boost::this_thread::get_id()))
class DatabaseException : public std::exception, public boost::exception { ... };
typedef boost::error_info< struct errinfo_message_, std::string > errinfo_message;
MY_THROW(DatabaseException(databaseHandle)
<< boost::errinfo_api_function("somefunction")
<< errinfo_message("somefunction failed terribly.")
);
This way you can catch specific exceptions while also providing loads of detail from the throw site (e.g., file name, line number, thread id, ...).
It also provides some pretty printing of the exception message and its details.
Most of the time I write that information in my log and abort the program, depending on the exception.
EDIT: As noted in the thread you cited, use shallow hierarchies. I use something like 3-4 exception classes that inherit directly from std::exception and boost::exception. I also put lots of details into the exceptions (e.g., the thread id).