I would like to define a completely generic mapping in c++ where I can map anything to anything.
I tried std::map but what should K and V be to make it general enough so I can map primitives or objects (as keys) to other primitives or objects (as values).
Or is there another mechanism I could use?
EDIT: For clarification, I am trying to define a relationship in the base class (from which all my classes are derived) that will allow me to attach arbitrary data to my classes. The simplest approach would be a be a name-value pair, where the above key is a string. I was wondering if i do something more generic?
Impossible- as it should be. Such a mapping would be worthless, since you can't depend on any meaningful behaviour of either key or value, and it's impossible to design either a binary relation or hash function that would be meaningful across "anything", or that could operate on any type, so it's nowhere near even the realm of possible.
Edit: There is nothing preventing std::unordered_map<std::string, boost::any>- or indeed, boost::any which happens to hold a std::unordered_map of some types.
However, your design appears highly questionable. You're basically completely subverting the compiler for no apparent benefit. Why would you derive every class from a common base? And why on earth would you want to attach arbitrary data? The usual way to put data in a class is to put it in the class, not blow all your safety and performance and sanity by trying to coerce C++ into being an interpreted language.
It is possible - so in this point I disagree with #DeadMG.
It is worthless - in this point full agreement,
However I do not understand that concept of answering, I mean "don't do it" answers instead "it can be done in this way, but my advise is don't do it". I do not pretend to be "life teacher" - I am just answering,
For values - use something like boost::any.
For keys - it is more complicated - because std::map defines order in keys. So generic keys must follow thess rules:
If real keys types are the same - use order from the real keys
If real keys are not the same - you must define order between types (like order of typeinfo::name())
Generic keys must be copy constructible
Let see my proposal for keys (using type erasure):
template <typename T>
struct GenKeyTypeOrder;
class GenKeyImplInt {
public:
// true if before other Key in other
virtual bool before(const GenKeyImplInt&) const = 0;
// type value
virtual int typeOrder() const = 0;
virtual GenKeyImplInt* clone() const = 0;
virtual ~GenKeyImplInt() {}
};
template <typename RealKey>
class GenKeyImpl : public GenKeyImplInt {
public:
GenKeyImpl(RealKey realKey) : realKey(realKey) {}
// true if before other Key in other
virtual bool before(const GenKeyImplInt& r) const
{
const GenKeyImpl* rp = dynamic_cast<const GenKeyImpl*>(&r);
if (rp) return realKey < rp->realKey;
return typeOrder() < r.typeOrder();
}
// type value
virtual int typeOrder() const { return GenKeyTypeOrder<RealKey>::VALUE; }
virtual GenKeyImpl* clone() const { return new GenKeyImpl(*this); }
private:
RealKey realKey;
};
class GenKey {
public:
// true if before other Key in other
friend bool operator < (const GenKey& l, const GenKey& r)
{
return l.impl->before(*r.impl);
}
template <typename T>
GenKey(T t) : impl(new GenKeyImpl<T>(t)) {}
GenKey(const GenKey& oth) : impl(oth.impl->clone()) {}
~GenKey() { delete impl; }
private:
GenKey& operator = (const GenKey& oth); // not defined
GenKeyImplInt* impl;
};
// define for every type you want be used as generic key
template <>
struct GenKeyTypeOrder<int> { enum { VALUE = 0 }; };
template <>
struct GenKeyTypeOrder<std::string> { enum { VALUE = 1 }; };
Full example at ideone
See also this article
You will need to make K and V be special objects.
The object will need to include what object type it is.
struct {
void *pointer;
string type;
// int type; // this is also possible
} Object;
The above Object can point to anything. However, it also needs something to say what type it is, hence the type string.
Then you need to be able to cast the pointer back to the required type, by reading what is in type.
Eg.
if (type == "int") cout << (int*)(myobject.pointer) << endl;
Anyways, if you do something like this, you are almost starting to build a loosely-typed interpreter, because for any operation you want to do with the object, you will need to check its type (whether you are adding, concatenating or printing the value to stdout).
It is probably better if you use a class object, and use inheritance to store any data you need.
class Object {
public virtual string to_string() {
return "";
}
};
Then if you want to store an integer:
class Integer : public Object {
int i;
public string to_string() {
char str[50];
sprintf(str,"%d",i);
return string(str);
}
public Integer operator=(int a) {
i=a;
return this;
}
};
This way you can define an interface of all the functions you want all objects to support.
Note that making the base Object class have virtual functions means that if you say:
Integer a;
a=5;
Object object = (Object)a;
cout << object.to_string << endl; // prints "5"
So that the function called is that defined by the actual (true) type of the object.
Related
EDIT: Total Overhaul
I am making a programming language (similar to Python), and at least for now, I am trying to compile it to C++. I'm having an error where C++ is saying that there is no member "value" in the class "Object". This is a compilation error. I understand why C++ is doing this, as it has to know the type of value at compile-time, and so I am asking for alternatives.
The only things it will be given are instances subclasses of Object, in which the member "value" will be defined, this is a compile error.
I can't declare the member "value" inside the Object class, because its type depends on which subclass it's in. This also has to work with floats and strings, so defining the function with an Integer instance instead of an Object instance won't work.
Here is some code with an example of how these objects will be used:
auto user_i = std::make_unique<Integer>(2);
std::cout << (*user_i).equals(*std::make_unique<Float>(2.0).get()) << std::endl;
Here are the important class definitions:
class Object {
public:
bool equals(Object& other) {
throw "Not implemented!";
}
};
class Integer: public Object {
public:
int value;
Integer(int val) {
value = val;
}
bool equals(Object& other) {
return value == other.value;
}
};
class Float: public Object {
public:
double value;
Float(double val) {
value = val;
}
bool equals(Object& other) {
return value == other.value;
}
};
class String: public Object {
public:
string value;
String(string val) {
value = val;
}
bool equals(Object& other) {
return value.compare(other.value) == 0;
}
};
It should not be the case that 2 == "2", but it should be the case that 2 == 2.0 == 2.000 etc.
There is then the added complication of methods like add (by this I mean returning a value, still not modifying the object). The equals method suggested by #Michael Karcher would work fine, but for example 2+3 should return 5, not 5.00000.
For even more trouble, User-Defined Objects (Classs in my language) should be able to override methods like add.
Your example has a couple of issues besides you main issues. I start with the minor issues to get them out of the way.
You need declare equals as virtual in the base class. Opposed to Java, dynamic dispatch is not the default in C++, but must be requested per method using the virtual attribute like this:
class Object {
public:
virtual bool equals(Object other) {
throw "Not implemented";
}
}
You are passing the object you compare to by value. Opposed to Java, in C++ even class types can be passed by value. This means that the function equals gets a copy of an Object to compare to - and just that. The parts of the object you want to compare to, including the value member, do not get copied into the argument passed to equals. You should pass the parameter by reference. As your equals function does not need to modify the object you compare to, a reference without write permission (commonly called a const reference due to the syntax) is enough:
class Object {
public:
virtual bool equals(const Object& other) {
throw "Not implemented";
}
}
If you are writing a base class that just provides a function signature which needs to be overridden in every derived class, you don't make it throw something, but you instead make it abstract by declaring it as a pure virtual function, using the =0 syntax. This prevents you from accidentally creating Object instances that can not be compared. This would have caught the missing pass-by-reference:
class Object {
public:
virtual bool equals(const Object& other) = 0;
}
Now, let's address your question:
This approach works in dynamically typed languages like JavaScript or Python, but it does not work in C++. During compilation, the compiler has to know where it finds the member value in the object other and its type. If you just pass in any Object, the compiler has no way of knowing it. And even you don't know: The type might be int or float. So neither you nor the compiler know whether there is a float value or an int value in the object you pass for comparison. If Integer objects should be comparable to both Integer and Float objects, you either need to comparison methods or you need a way to get a generic value of a common type. In this case, on machines with 32-Bit integers, every integer value is exactly representable in a double variable. You could add a second function to the Object class called as_double like this:
class Object {
public:
virtual bool equals(const Object &other) const = 0;
virtual double as_double() const = 0;
}
I also marked the methods const, which means you may call them on objects or using references you may not write to. Now you can implement Integer and Float like this:
class Integer: public Object {
public:
int value;
Integer(int val) {
value = val;
}
bool equals(const Object & other) const {
return value == other.as_double();
}
double as_double() const {
return value;
}
};
class Float: public Object {
public:
double value;
Float(double val) {
value = val;
}
bool equals(const Object & other) const {
return value == other.as_double();
}
double as_double() const {
return value;
}
};
And, if you look at the equals method, its now nearly the same for both types: You extract the value of argument as double, and compare it to the local value (in the case of Integer, the local value gets implicitly converted to double, too. So you could also use a generic comparison implementation that calls to_double on both objects, and you don't have to bother implementing equals in each subclass:
class Object {
public:
bool equals(const Object& other) const {
return as_double() == other.as_double();
}
virtual double as_double() const = 0;
}
Note, this only works because double actually is able to represent all values - even those stored in Integers. If your actual use-case does not have such a common type you can convert to, you need a more complicated solution.
Note that:
C++ is not a dynamically typed language, but a statically typed language. A variable's type is determined at compile time, and not runtime.
To have dynamic nature with the type, you need to have a polymorphic class - i.e. class having virtual functions. Through one or more virtual functions, you achieve the dynamic nature of the (class) type. The derived type (class) would (re)implement the necessary virtual functions
If you want to have types that seem dynamic but are static at compile time; then you can use templates. For example, an Add function can be:
template<typename Type>
Type Add(Type a, Type b)
{
return a+b;
}
And call them with any type:
Add(1,2); // int
Add(4.5, 5.0); // double
In the function, if you want to know the type, you can use certain helper functions like is_same:
Type Add(Type a, Type b)
{
if(std::is_same<Type, int>::value)
{
// Do whatever when 'int' is passed
}
...
}
The same approach can be used in class templates also. You may have (partial) template class specialization. vector with type bool is one example.
std::distance and std::advance are another examples which rely on the type of the container (in a simlpe sense) and are implemented differently (random access or sequence access).
The equal functions uses Object as the parameters type. Calling other.value does not work as you already pointed out Object does not have a parameter value. From the compiler point of view it will never get anything with a parameter value.
I suggest you rewrite the function definitions of equals to bool equals(Integer& other) and bool equals(Float& other).
I'm trying to add dynamic reflection in C++ implementation with C++11.
Let's say, I have a base class named Object:
class Object {
public:
Object() = default;
~Object() = default;
};
And two classes inherited from Object:
class Person : public Object {
public:
std::string name;
int age;
}
class Group : public Object {
public:
std::string groupName;
std::vector<Person> persons;
}
I've implemented RefectManager to record all the classes' meta information, and I create an object with a class name, for example:
Object *obj = RefectManager::CreateObject("Group");
MetaInfo *groupMeta = obj->GetMetaInfo();
where, "groupMeta" holds the meta information of class Group, it knows that:
class Group has a field list with two fields inclued:
* one field named "groupName", and its type's name is "std::string"
* one field named "persons", and its type's name is "std::vector" and the name of the element's type in the vector is "Person"
I can get the Person's meta information through its name:
MetaInfo *personMeta = RefectManager::GetMetaInfo("Person");
But, is there a way to enumerate the field of "persons" in class Group with reflected meta informations dynamically, such as:
for (field in groupMeta's field list) {
if (field type's name is "std::string") {
get field's content as string
} else if (field type's name is "std::vector") {
// only the element type's name is known as "Person"
// **how to enumerate the field with vector type?**
// If we know the element's type through element type's name,
// we can do it as following:
// std::vector<GetType<"Person">::type> *p = (std::vector<GetType<"Person">::type> *)field;
// std::vector<GetType<"Person">::type>::iterator it = p->begin();
// for (; it != p->end(); ++it) {
// //now we can access the element in field
// }
}
}
Thanks to Yakk, I have it done with lambda function to do type erasing.
When generating class member's meta info, I'll also generate a lambda function with it.
Thus, when doing enumerating a container, let the lambda function to do it, that's all.
Thanks Yakk again!
A vector<int> and a vector<bool> and a vector<Person> are unrelated types.
You are saying "they are all vectors, with different content", but in C++ templates produce types. std::vector isn't a type, it is a factory of types.
We can still do something here. We can talk about what operations a vector supports, and what we care about.
Suppose we only want to be able to read our vectors. In fact, we only want to be able to iterate!
Start with the idea of having an any_view, where an any_view is a view of anything (like a void* but smarter). Now a vector<Foo> is a kind-of range<any_view>.
This "view" concept splits values from references or pointers-to values. Your Object type is suitable for a value, not for a view of a value.
Most of the stuff you can do to an Object* are the kind of operations you want on an any_view; but the any_view doesn't own what it is viewing unlike an Object.
The interface (ignoring details) looks something like this:
template<class It>
struct range_t{
It b, e;
It begin() const { return b; }
It end() const { return e; }
bool empty() const { return begin()==end(); }
// etc
};
template<class X>
struct any_input_iterator{
// implement a boost-like type erasure wrapper around
// the concept of input iteration (read only single-pass iteration)
using self=any_forward_iterator;
friend bool operator==(self const&, self const&);
friend bool operator!=(self const&, self const&);
self& operator++();
self operator++(int);
X operator*()const;
using value_type = std::remove_reference_t<X>;
using reference = X;
// etc
};
template<class X>
using iterable_over = range_t< any_input_iterator<X> >;
struct any_view {
std::typeinfo const* get_typeid() const;
template<class T>
T* get_as() const;
iteratable_over<any_view> members() const;
};
We then write traits classes that generates the back-end data that describes what an any_view of a type T looks like, and write converting constructors that take a T& and generates an any_view. any_view holds a pointer to manual vtable of function pointers that implement the details, and a void* pointing at the T&, and dispatches its methods to it (passing in the void*).
This isn't easy, but it is a roadmap to a solution. A full solution is a bit much for a single stack overflow post.
In particular, type erasing type erasure where we wrap super_any containing std::refs for our any_view, and we type erase the operation of "get members", then we use an ADL free function or traits based method to describe the members and how to get them, would work.
After all this is done, your code might look like:
for (auto field : data) {
if (*field.type_id() == typeid(std::string)) {
std::string s = *field.get_as<std::string>();
} else if (!field.members().empty()) {
for (auto&& e:field.members()) {
if (*e.second.type_id() == typeid(Person)) {
Person& p = *e.get_as<Person>();
}
}
}
}
note in this abstraction, a vector is just something with a pile of members, which are the elements. Making it different can also be done.
As the title suggests, I am looking for a fast way of runtime typechecking. To illustrate my problem, imagine you have a class hierarchy like the following:
Base
/ \
A D
/ \ / \
C B F E
\ /
G
My program holds all instances of any class in a single list as Base_ptr because all these classes share common tasks. Now at some point some derived classes will need to know about the existence of an instance of another class. So far so good, I know about dynamic_cast and the typeid()-operator, but both have some mayor drawbacks:
dynamic_cast consumes a lot of processing time if the types are incompatible (e.g. try to cast instances of E to C)
typeid() does not work in "isTypeOrSubtype"-cases, e.g. you need all instances of D or derived from D (so Es, Fs and Gs as well)
The ideal solution would be some kind of "isTypeOrSubtype"-test and only casting, if this test returns successfully. I got an own approach with some macro definitions and precalculated classname hashes, but it is very ugly and hardly maintainable. So I am looking for a cleaner and faster way of dynamic type and subtype checking that can check far more than 20million times per second.
I wrote an answer to my own question as this is a different approach to avoid RTTI but no real answer to a fast way of dynamic type/subtype check.
This still isn't a clean solution, but the best I could think of until now.
If every class in this hierarchy has the following characteristics, I can skip most of the RTTI.
every class should have a private member: static SecureVector<[class]*> s_Instances; where SecureVector<T> is a thread-safe vector.
at the end of every constructor, s_Instances.push_back(this); should be called, to keep track of a newly created instance of that class
at the beginning of the destructor, s_Instances.erase(this); should be called, to remove this instances reference
every class should have a public function: static const SecureVector<[class]*>& Instances() { return s_Instances; } to get an unmodifiable vector containing all instances of this or any derived class
What this does is, every time a constructor is called, the instance adds itself to its own list of instances. When derived classes call their super constructor, the super class adds itself to its respective list of instances.
E.g. if I randomly create 100 instances in the above hierarchy, there would allways be 100 entries in my Base class Instances() vector.
In code this would look like this:
class Base
{
static SecureVector<Base*> s_Instances; // 1. condition
public:
Base()
{
s_Instances.push_back(this); // 2. condition
}
~Base()
{
s_Instances.erase(this); // 3. condition
}
static const SecureVector<Base*>& Instances() { return s_Instances; } // 4. condition
};
This is still just as a workaround as the four conditions have to be added manually (or by macro or something like it).
Some time ago I used something like this:
// the actual type is irrelevant, const char*, int, ...
// but const char* is great for debugging, when it contains the actual class name
typedef const char* TypeId;
class Base {
// actually the type id is not the value, but its memory location !
// the value is irrelevant (but its a good idea to set it to the class name)
static TypeId s_myTypeId;
public:
static TypeId* getClassType() { return &s_myTypeId; }
virtual TypeId* getInstanceType() { return &s_myTypeId; }
static TypeId* getClassBaseType() { return NULL; }
virtual TypeId* getInstanceBaseType() { return NULL; }
virtual bool isType( TypeId* type ) { return type==getInstanceType(); }
virtual bool isTypeOrSubType( TypeId* type ) { return isType(type); }
};
template< class MyBase >
class TBase : public MyBase {
// actually the type id is not the value, but its memory location !
// the value is irrelevant (but its a good idea to set it to the class name)
static TypeId s_myTypeId;
public:
static TypeId* getClassType() { return &s_myTypeId; }
virtual TypeId* getInstanceType() { return &s_myTypeId; }
static TypeId* getClassBaseType() { return MyBase::getClassType(); }
virtual TypeId* getInstanceBaseType() { return MyBase::getInstanceType(); }
virtual bool isType( TypeId* type ) { return type==getInstanceType(); }
virtual bool isTypeOrSubType( TypeId* type ) { return isType(type) || MyBase::isTypeOrSubType(type); }
};
// by deriving from TBase<Base>, a new instantiation of s_myTypeId was created,
// so the class now has its very own unique type id,
// and it inherited all the type resolution magic
class A : public TBase<Base> {
};
// NOTE: class B must not derive directly from A, but from TBase<A>
// imagine a hidden class between B and A,
// actually B inherits from the TBase<A> instantiation, which in turn inherits from A
class B : public TBase<A> {
};
// you will also need to instantiate the static members
// hereby the memory location will be reserved,
// and on execution that memory location becomes the unique type id
#define IMPLEMENT_RTTI(CL) TypeId CL::s_myTypeId = STRFY(CL)
// one per class per source file:
IMPLEMENT_RTTI(Base);
IMPLEMENT_RTTI(A);
IMPLEMENT_RTTI(B);
// example usage:
A a;
B b;
b.getInstanceType()==B::getClassType(); // TRUE
b.getInstanceBaseType()==A::getClassType(); // TRUE
B::getClassBaseType()==A::getClassType(); // TRUE
b.isType( B::getClassType() ); // TRUE
b.isType( A::getClassType() ); // FALSE
b.isTypeOrSubType( B::getClassType() ); // TRUE
b.isTypeOrSubType( A::getClassType() ); // TRUE
b.isTypeOrSubType( Base::getClassType() ); // TRUE
It is safe, fast and easy to use. You just have to obey two rules:
do not inherit directly from a class X, but inherit from TBase<X>,
and add an IMPLEMENT_RTTI(Me) to source file.
There is one drawback: it does not yet support multiple inheritance. But it would be possible with a few changes.
And probably the TypeId type should be composed like typedef const char* TypeLoc and typedef TypeLoc* TypeId. Maybe just a question of taste.
If your program knows about all the sub types that will be tested against, you can use a virtual interface that returns a pointer to the sub type. As noted by downvotes and comments, this is not the most flexible approach, since it requires the base class have knowledge of all the derived classes. However, it is very fast. So there is a trade off of flexibility to performance.
class Base {
//...
virtual A * is_A () { return 0; }
virtual B * is_B () { return 0; }
//...
template <typename MAYBE_DERIVED>
MAYBE_DERIVED * isTypeOrSubtype () {
//...dispatch to template specialization to call is_X()
}
};
//...
class A : virtual public Base {
//...
A * is_A () { return this; }
};
On IDEONE, the suggested technique is 20 to 50 times faster than using dynamic cast.1 The implementation uses macros to allow a new class to be added to a single place, and the proper expansions to the base class occur in an automated way after that.
(1) - I originally clocked it closer to 100 times as fast, but this was without the isTypeOrSubtype() wrapper method that I added to simulate the desired interface.
If flexibility has a higher value than performance, then a slightly less performant solution is to use a map to associate types and corresponding pointer values (having the pointer values removes the need for a dynamic cast). The map instance is maintained in the base class, and the associations are made by the constructors of the subclasses. Whether a regular map or a unordered_map is used will depend on how many subclasses virtually inherit the base class. I would presume the numbers will be small, so a regular map should suffice.
class Base {
std::map<const char *, void *> children_;
//...
template <typename MAYBE_DERIVED>
MAYBE_DERIVED * isTypeOrSubtype () {
auto x = children_.find(typeid(MAYBE_DERIVED).name());
return ((x != children_.end())
? static_cast<MAYBE_DERIVED *>(x->second)
: 0);
}
};
//...
class A : virtual public Base {
//...
A () { children_[typeid(A).name()] = this; }
//...
};
On IDEONE, this second suggestion is 10 to 30 times faster the using dynamic cast. I don't think IDEONE compiles with optimizations, so I would expect the times to be closer to the first suggestion on a production build. The mechanism as implemented uses typeid(...).name() as the key to the map.2
(2) - This assumes that typeid(...).name() returns something similar to a string literal, and always returns the same string pointer when operating on the same type. If your system does not behave that way, you can modify the map to take a std::string as the key instead, but performance will be degraded.
dynamic_cast would work wonderfully for this!
Base *instance = //get the pointer from your collection;
A* ap = dynamic_cast<A*>(instance);
D* dp = dynamic_cast<D*>(instance);
if(ap) {
//instance is an A or a subclass of A
}
if(dp) {
//instance is a D or a subclass of D
}
This will work for more specific checks as well. So you could check for any type you want.
I'm trying to solve the following problem. I have a vector (it's a custom structure actually, but a vector is a good enough substitute for this issue) of pointers to a custom class A. Class A can actually store either a type_a pointer or a type_b pointer (these types are quite different and are not related to each other). Right now that's implemented by keeping both, setting them to NULL and then having a bunch of if/else statements later on to check which type it is and perform appropriate action.
class A {
public:
A() : p1(NULL), p2(NULL) {}
type_a * p1;
type_b * p2;
};
std::vector<A *> v;
...
if (v[0]->p1 != NULL) { /* do this */ }
else if (v[0]->p2 != NULL) { /* do that */ }
I plan to add more pointers to class A, and so the above is starting to become a hassle. The solution that I'm currently trying to make work is using boost::variant instead, to have:
class A {
public:
boost::variant<type_a*, type_b*> p;
};
The problem I have encountered though, is that one of my actions involves calling a function that would assign some values to a variable depending on what type of p I have. This is what it is now and the appropriate process_stuff function is called inside one of the above if/else statements:
class B { /*...*/ };
void process_stuff(type_a * p, B * b) {
b->m_var = p->fn1();
}
void process_stuff(type_b * p, B * b) {
b->m_var = p->fn2();
}
I can't get this to work with boost::static_visitor since (as far as I understand) I can't have a non-variant type as an argument in binary visitation, nor can I have a non-const operator() to make the second variable a member of the visitor class and modify that inside operator() with unary visitation. So I'm confused how to convert the above process_stuff function to play along with boost::variant.
Btw I'm not attached to boost::variant and would take other solutions.
You just need a stateful visitor. I'm typing this from a vague memory of exactly what visitors look like, but you should be able to fix any mistakes I make.
class process_stuff_visitor : public boost::static_visitor<void> {
B* m_b;
public:
process_stuff_visitor(B* b) : m_b(b) {}
void visit(type_a* a) const { m_b->m_var = a->fn1(); }
void visit(type_b* b) const { m_b->m_var = b->fn2(); }
};
// actual processing:
boost::apply_visitor(v[0], process_stuff_visitor(the_b));
Alternatively since you assign to the same member of B, you could just extract the value-generating part.
struct generate_stuff_visitor : public boost::static_visitor<TypeOfMVar> {
TypeOfMVar visit(type_a* a) const { return a->fn1(); }
TypeOfMVar visit(type_b* b) const { return b->fn2(); }
};
the_b->m_var = boost::apply_visitor(v[0], generate_stuff_visitor());
A very general object-oriented way of doing what you want to do (if I understand you correctly) is to create a virtual base class for types a and b (and any further types you want) which defines a pure virtual method. This method will return something different for each type (for example, type_b::method could return 'b', while type_a::method could return 'a'), so when you call the method on your unspecified type, you will be told what type it is.
From there, you can use the return value of the identifying method to be the subject of a switch statement, or some other conventional control structure to invoke the correct behavior.
Is it possible to store a type name as a C++ variable? For example, like this:
type my_type = int; // or string, or Foo, or any other type
void* data = ...;
my_type* a = (my_type*) data;
I know that 99.9% of the time there's a better way to do what you want without resorting to casting void pointers, but I'm curious if C++ allows this sort of thing.
No, this is not possible in C++.
The RTTI typeid operator allows you to get some information about types at runtime: you can get the type's name and check whether it is equal to another type, but that's about it.
Not as written, but you could do something similar...
class Type
{
public:
virtual ~Type(){}
virtual void* allocate()const=0;
virtual void* cast(void* obj)const=0;
};
template<typename T> class TypeImpl : public Type
{
public:
virtual void* allocate()const{ return new T; }
virtual void* cast(void* obj)const{ return static_cast<T*>(obj); }
};
// ...
Type* type = new TypeImpl<int>;
void* myint = type->allocate();
// ...
This kind of thing can be extended depending on what features you need.
You can't do that in C++, but you can use the boost any library then test for the type it holds. Example:
bool is_int(const boost::any & operand)
{
return operand.type() == typeid(int);
}
http://www.boost.org/doc/libs/1_42_0/doc/html/any/s02.html
No you can't store the type directly as you want, but you can instead store the name of the type.
const char* str = typeid(int).name();
I guess whenever you planned to use that variable for comparison, you could instead at that time compare the str variable against the name() of the types.
const char* myType = typeid(int).name();
//....
//Some time later:
if(!strcmp(myType, typeid(int).name()))
{
//Do something
}
More info available here
Yes, if you code it yourself.
enum Foo_Type{
AFOO,
B_AFOO,
C_AFOO,
RUN
};
struct MyFoo{
Foo_Type m_type;
Boost::shared_ptr<Foo> m_foo;
}
as commented below, what I left out was that all these "foo" types would have to be related to Foo. Foo would, in essence, be your interface.
Today I had a similar problem while coding:
I had the need to store a polymoriphic data type (here named refobj) over wich call functions of the concrete classes implementing it. I need a solution that doesn't cast the variable explicitly because I need to reduce the amount of code.
My solution (but I haven't tested it yet) looks similar to a previous answer. Actually is quite an experimental solution. It look like this...
// interface to use in the function
class Type
{
public:
virtual void* getObj()const=0;
};
// here the static_cast with the "stored" type
template<typename T> class TypeImpl : public Type
{
public:
TypeImpl(T *obj) {myobj=obj;}
virtual void* getObj()const{ return static_cast<T*>(myobj); }
private:
T* myobj;
};
// here the type that will contain the polimorific type
// that I don't want to cast explicitly in my code
Type *refobj;
// here the "user code "
void userofTypes()
{
( refobj->getObj() ).c_str();
// getObj() should return a string type over which
// calling string concrete functions ...let's try!
}
void main()
{
refobj=new TypeImpl < string > ( new string("hello") );
userofTypes();
}
// it might seem absurd don't cast refobj explicitly, but of
// course there are situation in which it can be useful!
Types are not objects in C++ (where they are in Ruby, for instance), so you cannot store instances of a type. Actually, types never appear in the executing code (RTTI is just extra storage).
Based on your example, it looks like you're looking for typedefs.
typedef int Number;
Number one = 1;
Number* best = (Number*) one;
Note that a typedef isn't storing the type; it is aliasing the type.
A better process is to have a common base class containing a load method, and an interface for loaders. This would allow other parts of the program to load data generically without knowledge of the descendant class:
struct Load_Interface;
struct Loader
{
virtual void visit(Load_Interface&) = 0;
}
struct Load_Interface
{
virtual void accept_loader(Loader& l)
{
l.visit(*this);
}
};
This design avoids the need to know the types of objects.