Archived

This topic is now archived and is closed to further replies.

True 'AnyType' in C++

This topic is 5087 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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++?

Share this post


Link to post
Share on other sites
Long story short: not really.

However, one thing that could be done is store everything as strings. Then provided that all your types properly implement operator<< and operator>> you can convert things through stringstreams.

Share this post


Link to post
Share on other sites
I guess that is one way, but its not really viable. Constantly converting the types to/from a string would be very processor intensive =-/

[edited by - extrarius on January 5, 2004 2:05:23 PM]

Share this post


Link to post
Share on other sites
I'm writing an interpreter, and using strings to store things would would mean running the value through the interpreter over and over.

[edited by - extrarius on January 5, 2004 2:14:42 PM]

Share this post


Link to post
Share on other sites
Well, other methods exist, but they tend to be type intensive. For example, type flag techniques. Without a better idea of what you''re trying it''s hard to give good advice here.

Share this post


Link to post
Share on other sites
if you have control over what this 'type' is then you could have a base class which everything is derived from. I can't see that being very useful on the whole. Usually runtime type information is useful for debugging and for editors. Are you wanting to make a scripting language or something? If you are I wouldn't worry too much about performance to start with.

[edited by - petewood on January 5, 2004 2:56:59 PM]

Share this post


Link to post
Share on other sites
maybe imjust talking out my ass, but u could have like context tables and interlink between and out of them. use the pointers to those tables, or have like a structure which has both type and pointer too.

variable
[
type enumVar;
void* myVarPtr;
]

call to new or malloc for 64 128 or 32 bit variants.
i would need more information on how you plan on storing and arranging variable execution with in your interpreted language before making a final call though

Share this post


Link to post
Share on other sites
I think the last few posters misunderstood my question. I don''t need a union that can hold one of 3-4 different types, I''m trying to make something simmilar to boost::any that can hold ANY type and doesn''t need to know anything about the types it can hold.
The problem with boost::any (well, not really a problem but something I''d like to change) is that in order to extract a value from it after you have stored the value, you have to know what type it is (which you can find out using the type method, which returns type_info of the type currently being stored and several if statements, but you have to know which types you''re going to handle to do that). I want to be able to say ''return the stored value as a float''(like float f = anyType.GetValue<Float>()) and if possible it will convert it to a float (if not, it should throw, or maybe it returns a pointer and returns null if it can''t convert). Right now, the boost::any class only allows you to retrieve the value in the type stored (if it is storing an int and you ask for a float, it will return a float pointer that points to the location of the int rather than converting the number stored)

Share this post


Link to post
Share on other sites
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)

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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).

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
"Game Scripting Mastery" describes the implementation of a
typeless scripting language, which sounds like is what you''re
doing here.

The basic idea is already mentioned -- to use a type flag.
Then provide some auxiliary functions like GetValueAsInt(),
GetValueAsString(), GetValueAsBoolean()...etc.

Those functions attempt to convert from whatever internally
stored value to whatever format is requested.




Kami no Itte ga ore ni zettai naru!

Share this post


Link to post
Share on other sites
quote:
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).

You shouldn''t be planning anything of the sort. You should add a few base types (perhaps, integers, floating point, strings, arrays, lists) and everything else should be built up within the scripting language itself.

Share this post


Link to post
Share on other sites
quote:
Original post by DrPizza
quote:
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).

You shouldn''t be planning anything of the sort. You should add a few base types (perhaps, integers, floating point, strings, arrays, lists) and everything else should be built up within the scripting language itself.

Right now I''m planning on integers, floating point, strings, arrays, lists, streams, functions, hash tables, characters, read-tables, and several others. I''ll probably add more as I go along to make my language more complete. I''m making a Common Lisp-based scripting language.

Share this post


Link to post
Share on other sites
Another solution is to use interfaces.. Although it isn''t the best because it requires you to create classes to hold all your basic types.


class ISomeType
{
void * GetObject(string vType) = 0;
};


You could have all your types implement that interface and whenever you want to convert it to a type just call GetObject with the name of the object.

Share this post


Link to post
Share on other sites