Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Boost.Any get original type

Tags:

c++

types

boost

I need to cast an any variable to an original type. I need to do this:

int i = 10;
any a(i);
int& i2 = any_cast<int &>(a);

But I want that the type stores in any variable. And I write this:

int i = 10;
any a(i);
a::type_value& i2 = any_cast<a::type_value &>(a); // there is no actually type_value

How can I do something like that? Or how can I extract the original type from the any variable? Boost.variant is convenient either.

If I cannot do that, then I have another question what C++ techniques and libraries can store and get the type through a function to solve this issue?

like image 355
Kron Avatar asked Feb 02 '12 00:02

Kron


People also ask

How does boost any work?

The key difference between boost::any and boost::variant is that any can store any type, while variant can store only one of a set of enumerated types. The any type stores a void* pointer to the object, as well as a typeinfo object to remember the underlying type and enforce some degree of type safety.

What is boost any?

The boost::any class (based on the class of the same name described in "Valued Conversions" by Kevlin Henney, C++ Report 12(7), July/August 2000) is a variant value type based on the second category. It supports copying of any value type and safe checked extraction of that value strictly against its type.

What is boost optional?

Boost C++ Libraries Class template optional is a wrapper for representing 'optional' (or 'nullable') objects who may not (yet) contain a valid value. Optional objects offer full value semantics; they are good for passing by value and usage inside STL containers.

What is boost variant?

Boost. Variant, part of collection of the Boost C++ Libraries. It is a safe, generic, stack-based discriminated union container, offering a simple solution for manipulating an object from a heterogeneous set of types in a uniform manner.


1 Answers

C++ is a statically typed language. The type of a boost::any is a runtime value; any particular any could have any type. That's kinda the point.

There is no any::type_value, because that would have to be a compile time value. And any is a runtime construct.

Consider this:

void TakeAnAny(boost::any a)
{
  a::type_value& i2 = any_cast<a::type_value &>(a);
}

What type is any::type_value? It is legal to call TakeAnAny with virtually any type. There is no single compile-time type that any::type_value could reduce to. And therefore, there is no way for the compiler to determine a type. Since C++ is statically typed, you're hosed.

The ultimate purpose of any is type-erasure. I have some value. And I want to pass that to some other function. This process will go through several different communication layers. But I don't necessarily want all of those different layers to know exactly what type I'm using. I only need myself and my intended destination to know the type. So you stick it in an any and you're fine. Everyone else just sees the any, and both of you know what it wraps.

This process only works because both the source and the destination know the real type of the value. If you don't know the type, then you shouldn't be using any. The purpose of any is not have a function sit there and cast it to a bunch of possible types (that's what boost::variant is for). The purpose is to erase the type from a function's signature.

This allows for things like generic messages and signals. You register some event handler with a system. You fire an event that takes an any as a parameter. The person firing the event knows that the "MouseClick" event always takes a vec2 as its parameter. So every "MouseClick" handler casts it to a vec2. The "KeyPress" event would maybe pass a int32_t. So those handlers cast it to that type. And so forth. Everyone knows what type it actually takes.

This used to be done with void*. The problem there is that you have ownership issues (any is a value, while void* is a pointer). Also, a void* is so type-erased that there's no way to check to see if your cast is correct. any is really just a type&value-safe void*; it prevents you from casting to the wrong type.

You don't really want any. Your use case doesn't seem to want variant either. What you seem to want is a template. That's a different kind of thing, and it would let you do what you really want: have a function that can use any particular type, while still being able to know exactly what that type is.

Of course, templates have their own limitations.

like image 71
Nicol Bolas Avatar answered Oct 25 '22 04:10

Nicol Bolas