Reputation: 4046
I'm not sure if this calls for boost::any
. I'd rather use native templates if there's a pattern that does what I want. I have this class (which I've written here using boost::any
) defined in a header:
template <typename T> class Observable;
class Report
{
typedef unordered_map<wstring, std::shared_ptr<Observable<boost::any>>> ObservationMap;
public:
void AddObservable(const wstring& name, std::shared_ptr<Observable<boost::any>> observable);
const Observable<boost::any>& GetObservable(const wstring& name) const;
protected:
ObservationMap observations;
};
and Observable
is defined like this:
template <typename T>
struct Observable
{
typedef T Type;
T Quantity;
// ...
};
I would really like some way of adding Observable
s of any quantity type to Report
s. Is there a more effective way of doing this without incurring the overhead of boost::any
?
Edit: An example of code that adds observables to the report class would be something like this:
Observable<float> obs1;
obs1.Quantity = 1.1f;
Observable<int> obs2;
obs2.Quantity = 5;
Report report;
report.AddObservable("Height", obs1);
report.AddObservable("Age", obs2);
Then somewhere else I would want to read those quantities. Say I receive the report:
void DoSomethingWithReport(Report& report)
{
float height = report.GetObservable("Height").Quantity;
int age = report.GetObservable("Age").Quantity;
}
Something like that. Of course, I'd really add other methods to check if those observations are present in the report, etc. I prefer it to be generic because I don't know beforehand, at the receiving site, what it will contain, so I'd like some flexibility.
Upvotes: 0
Views: 632
Reputation: 275500
boost::any
is a decently efficient way to store a value of a type you have prevented the compiler (for whatever reason or design requirement) from knowing.
If there are only a limited set of operations you want to perform on the data, you can use type erasure instead and/or a base interface class. But that requires knowing all uses for the data when you define the interface.
If you have a limited set of data types, boost::variant
or the like can be more efficient than any
. You can even have a variant
that includes any
or a type erasure object (or objects) in the set of types.
You can use reflection or similar techniques to store complex data and wrap it in any
accessors (or variant
) if your data is sometimes structured, which can reduce storage overhead somewhat. Basically structured data becomes a type erased type with member access by name.
Much of these techniques end up mirroring type behaviour of scripting or bytecode languages: sometimes it might be a good idea to write the part of your app that needs this amount of compile time flexibilty in a mainly runtime type checked language.
Finally you may decide you do not need all this needless runtime dynamic typing.
Upvotes: 3