简体   繁体   中英

boost::any confusion with pointers vs values

It took me a while to figure this out, but the semantics of boost::any are confusing.

With value types, you use it like so:

int value = 100;
boost::any something;
something = value;
//...later...
int value = boost::any_cast<int>(&something);

This code is clear and makes sense, but stores value internally as a copy. This means for larger objects I place inside boost::any , they will be copied. Also any functions that I replace void* with this will expect that the value outside the function is modified when I modify the value contained in the boost::any object (which won't happen, since it copied it).

So if I put pointers into it, things get weird:

int value = 100;
boost::any something;
something = &value;
//...later...
int* value = *boost::any_cast<int*>(&something);

I have to dereference the return value in this case because boost::any_cast returns int** ! I also haven't checked but I think this may crash if something.empty() == true . This is just not straightforward at all.

I do not want to store values in my boost::any , I want it to only function on pointers and behave semantically closer to void* . Pointers in, pointers out, with some type-safety mixed in. Essentially what I want is boost::any_pointer , or something like that. Is there a way to prohibit boost::any from accepting anything except pointers? And if not, is there an alternative to boost::any that can give me the semantics I'm looking for?

NOTE : I am assuming you want to store pointers in boost::any , since you are looking for something on the lines of boost::any_pointer (though non-existent).

boost::any_cast returns the pointer to the actual value stored inside it (the held object inside holder). So it kind of saves a copy unless you actually want to copy it later.

template<typename ValueType>
    ValueType * any_cast(any * operand) BOOST_NOEXCEPT
    {
        return operand && operand->type() == boost::typeindex::type_id<ValueType>()
            ? &static_cast<any::holder<BOOST_DEDUCED_TYPENAME remove_cv<ValueType>::type> *>(operand->content)->held
            : 0;
    }

You can always create a wrapper around boost::any to allow only pointer types:

class MyAny {
public:
  template <typename T, 
        typename = typename std::enable_if<std::is_pointer<std::remove_cv<T>::type>::value>::type>
  MyAny(T ptr): any_(ptr) {}

 template <typename ValueType>
 ValueType operator*() {
     return *boost::any_cast<ValueType>(&any_);
 }

private:
  boost::any any_
};

Above is a rough code, I have not compiled and tested it.

std::enable_if type trait is available in C++11, but can be found in boost as well. It is what that will constrain your MyAny to only pointer types.

You are using any_cast wrong:

There are essentially two (three) flavors.

  • Taking a reference to any and returning a value or reference to the content
  • Taking a pointer to any and returning a pointer to the content

Examples:

#include <boost/any.hpp>
int main()
{
    // Any holding a value
    {
        boost::any any_value(1);
        // Throws bad_any_cast if the content is not 'int' (in this case):
        int  value = boost::any_cast<int>(any_value);
        // Throws bad_any_cast if the content is not 'int' (in this case):
        int& reference = boost::any_cast<int&>(any_value);
        // Returns a null pointer if the content is not 'int' (in this case):
        int* pointer = boost::any_cast<int>(&any_value);
    }

    // Any holding a pointer (which is nothing else but a value)
    {
        int integer = 0;
        boost::any any_ptr(&integer);
        // Throws bad_any_cast if the content is not 'int*' (in this case):
        int * pointer = boost::any_cast<int*>(any_ptr);
        // Throws bad_any_cast if the content is not 'int*' (in this case):
        int*& pointer_reference = boost::any_cast<int*&>(any_ptr);
        // Returns a null pointer if the content is not 'int*' (in this case):
        int** pointer_pointer = boost::any_cast<int*>(&any_ptr);
    }
}

See also: http://en.cppreference.com/w/cpp/experimental/any and http://en.cppreference.com/w/cpp/experimental/any/any_cast

Although this is quite an old question, I nevertheless would like to point out a simple misconception [I think] in the preface of the asked questions:

int value = 100;
boost::any something;
something = &value;                                    // 1)
//...later...
int* value = *boost::any_cast<int*>(&something);       // 2)

1) This saved "int *" in something.

2) This contains essentially several steps:

  • "&something" gets the address of something, ie return "boost::any *"
  • "boost::any_cast()" now casts this address to a pointer to an int - which is probably not what void.pointer wanted. And I don't know whether - and if, why - this seems to work.
  • And then you dereference "*boost::..." this, ie cancelling the "&" from the first step again.

What I think, void.pointer wanted to do here, is more along the following line:

int* value = boost::any_cast<int*>(something);

.

PS: I would have liked to put this in a simple comment and not a full-fledged answer - stackoverflow however requires me to collect enough points first, so...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM