Boost.Any get original type

12,916

Solution 1

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.

Solution 2

You can use a map of std::type_info to std::function<void(boost::any const&)> object to deal with the types you are aware of and you want to deal with: you would locate the entry in the map using a.type() and call the corresponding function which would know how to deal with the argument.

Share:
12,916

Related videos on Youtube

Kron
Author by

Kron

Updated on June 04, 2022

Comments

  • Kron
    Kron almost 2 years

    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?

    • ildjarn
      ildjarn about 12 years
      You simply can't do this with Boost.Any, so using Boost.Variant instead is going to be the basic answer.
    • GManNickG
      GManNickG about 12 years
      Why do you need to do this?
  • ildjarn
    ildjarn about 12 years
    If one is aware of the types they're going to be dealing with, then why would one use Boost.Any instead of Boost.Variant in the first place?
  • Dietmar Kühl
    Dietmar Kühl about 12 years
    It seems a simpler type to pass along. Also, there may be interfaces which take boost::any as arguments and eventually call a function where the boost::any is given back in some form. For example, it seems that attaching a boost::any to an object to hold arbitrary information is a reasonable thing and the user of the class may very well know which types he might attach.
  • ildjarn
    ildjarn about 12 years
    Given that specific scenario then I agree that boost::any<> may be appropriate; after all, the library does exist for a reason. But somehow I doubt the OP is in that specific scenario, and I would still vote for Boost.Variant unless the OP has a specific reason that's not feasible. ;-]