True 'AnyType' in C++

Started by
28 comments, last by Extrarius 20 years, 3 months ago
You have tried boost::any, but have you tried boost::dynamic_any (available from the CVS repository, I believe) ? Or Alexandrescu''s discriminated unions (CUJ articles, probably integrated into Loki by now) ? In the Boost Yahoo group files, there was a module that would let do an any converting cast (any_ccast) for which exact matching was not required, so long as you had registered a conversion function from the actual to the desired type.


“Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.” — Brian W. Kernighan (C programming language co-inventor)
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Advertisement
You should be able to use simple templated functions and variables to do this. If you don''t know how, just google for templated functions in c++ or whatever.
dynamic_any hadn''t made it into the boost CVS last time I checked, but Nasonov has a sourceforge project for it. Personally, I find the entire design very awkward.

Also, discriminated unions hadn''t made it into Loki as of it''s last release (and from what Extrarius said, I don''t think they''re quite what he had in mind either). However, the CUJ articles for it are still online.

ms291052: I don''t think you understood the question, or you have a misunderstanding about the capabilities of templates.
quote:Original post by SiCrane
dynamic_any hadn''t made it into the boost CVS last time I checked, but Nasonov has a sourceforge project for it. Personally, I find the entire design very awkward.


Yeah, you''re right, I just checked. boost::Variant (a discriminated union) is in there though.

I think any_ccast is what he wants.

Yet, I don''t think he''ll get around having to register his types one way or another.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Fruny, is there another source for any_ccast? Yahoo groups is being grumpy about accepting my login, and I don''t seem to be able to find another reference on it.

One thought I had was doing a caching system on the string storage implementation. Something like:
#include <iostream>#include <string>#include <map>#include <boost/lexical_cast.hpp>#include <boost/smart_ptr.hpp>#include <loki/LokiTypeInfo.h>#include <complex>class Holder {  private:    struct BaseHolder {      virtual ~BaseHolder() {}    };    template <typename T>    struct HolderHelper : BaseHolder {      T value_;      HolderHelper(const T & t) : value_(t) {}    };    std::string value_;    typedef std::map< Loki::TypeInfo, boost::shared_ptr<BaseHolder> > CacheMap;    CacheMap cache_;  public:    Holder() : value_("") {}    ~Holder() {}    template <typename T>    void Store(const T & t) {      value_ = boost::lexical_cast<std::string>(t);      cache_.clear();      boost::shared_ptr<HolderHelper<T> > p(new HolderHelper<T>(t));      cache_[typeid(t)] = p;    }    template <typename T>    const T & GetAs(void) {      CacheMap::iterator i = cache_.find(typeid(T));      if (i != cache_.end()) {        boost::shared_ptr<BaseHolder> p = (*i).second;        BaseHolder * pBase = p.get();        HolderHelper<T> * q = dynamic_cast<HolderHelper<T> * >(pBase);        assert(q);        return q->value_;      }      T temp = boost::lexical_cast<T>(value_);      HolderHelper<T> * p = new HolderHelper<T>(temp);      boost::shared_ptr<BaseHolder> q(p);      cache_[typeid(T)] = q;      return p->value_;    }};int main(int argc, char **) {  Holder h;  h.Store<int>(5);  float f = h.GetAs<float>();  std::cout << f << std::endl;  std::complex<float> cf = h.GetAs<std::complex<float> >();  std::cout << cf << std::endl;  return 0;}

Warning: some pretty horrible exception safety issues.

Compared to a full lexical conversion through the string, looking up the type info structure and the lookup in the std::map can be relatively inexpensive, depending on the type.
quote:Original post by Extrarius
For a project I''m working on, I need a class that can hold any type of value. For this, there is boost::any, BUT, in order to get the value you need to know what type it is and use the templated any_cast to get the value.
I need to be able to get the value converted to a specific type without knowing what type the value was perviously. Is there any way to do this in C++?


I''ve not understood...if you know nothing about your data you cannot convert it to a specific type...if you specify a type you specify also a conversion rule (from ''unknown'' type to ''specified'' type).
If you need to handle number you can use long double (or double) as ''number containers''; you can also use string to manage string (obviously) and numbers and every object that implements a conversion to/from strings.
You can use different solutions but you should provide methods (something like virtual functions in a base CObject) that converts derived (''unknown'') objects to specific types.
quote:Original post by SiCrane
std::map can be relatively inexpensive, depending on the type.


If your system provides it, you should use std::hash_map, I believe.
quote:Original post by MaulingMonkey
If your system provides it, you should use std::hash_map, I believe.

Most hash_map implementations tend to perform worse than std::map for a small number of inserted values. Besides which, type_info objects tend not to hash well.
blizzard999: Well, the ideal situation would be that I give a class some conversion operators, when I try to convert the generic type to a specific type, it would call the appropriate conversion operator. If template virtual methods were supported, it would be easy and just take an addition to the ''holder'' type of boost::any and then adding a passthrough in the any type itself.

Looking at boost::variant and boost::dynamic_any (actually I only found an example of somebody having problems with dynamic_any, but from the looks of that), they are not what I want. I really don''t want to have to define the conversion operators several ways, and I don''t want the type to be limited to a subset of types.

I don''t need this really, it would just be much more convenient since it would alleviate the repetition of if(a.type() == typeid(x)) y = static_cast<y_type>(any_casy<x_type>(a))(well, that might have errors but you get the idea) in several places. Since I plan on adding lots of types to my scripting language, I''d rather not have to do something like variant where you list the types you want {because I''m not sure the number of types I''ll have in the end is less than the maximum it lets you specify).
"Walk not the trodden path, for it has borne it's burden." -John, Flying Monk
Mirrored for your viewing pleasure. Limited time offer.

Extrarius - I really don't want to have to define the conversion operators several ways, and I don't want the type to be limited to a subset of types.

You have no choice, really. C++ is statically typed. You *will* have to maintain a list of types and conversion functions. Writing your modules in Objective-C is an option you should consider. (note that Obj-C can only be directly mixed with C, not C++)

[edited by - Fruny on January 5, 2004 10:53:09 PM]
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan

This topic is closed to new replies.

Advertisement