Is there a way to access the internal pointer of std::any using std::any_cast?

618 Views Asked by At

I can't get std::any running properly in the following peace of code. What I'd like to achieve is to return a reference/ pointer to the object hold by std::any. The version below using a void pointer is just running fine.

How can I translate that using std::any.

Why is std::any_cast designed to return a copy of the internal object anyway?

Thank you!

struct ReadOperation
{
  public:
    template <LeafnodeConcept L> 
    static bool visitLeafnode(L *l)
    {
        value = &(l->data);
        return false;
    }

    template <NodeLike N> static bool previsit(N* n)
    {
        return false;
    }

    template <class T> 
    static const T GetValue()
    {
        // return std::any_cast<T>(value);
        return *static_cast<T*>(value);
    }

    template<class T>
    static const T* GetValueRef()
    {
        return static_cast<T*>(value);
    }

  private:
    // inline static std::any value = nullptr;
    inline static void* value = nullptr;
};
1

There are 1 best solutions below

0
On

Thank you for pointing out the right way to use std::any_cast in the comments. I created a sample which seems to work as expected.

#include <iostream>
#include <any>
#include <array>

struct ReadOperation
{
    template <class T>
    static void SetValue(T&& v) 
    {
        value = std::forward<T>(v);
    }
    
    template <class T> 
    static const T GetValue()
    {
        return std::any_cast<T>(value);
    }

    template<class T>
    static const T* GetValuePtr()
    {
        return std::any_cast<T>(&value);
    }
    
    template<class T>
    static const T& GetValueRef()
    {
        return std::any_cast<T&>(value);
    }

  private:
    inline static std::any value = nullptr;
};

int main()
{
    std::array<uint8_t, 12> arr { "hello world" }; 
    ReadOperation::SetValue(std::move(arr));
    
    // Returns a constant pointer
    const std::array<uint8_t, 12>* foo1 = ReadOperation::GetValuePtr<std::array<uint8_t, 12>>();
    std::cout << foo1->data() << std::endl;
    
    // Returns a constant reference 
    const std::array<uint8_t, 12>& foo2 = ReadOperation::GetValueRef<std::array<uint8_t, 12>>();
    std::cout << foo2.data() << std::endl;
    
    // Retruns a copy 
    const std::array<uint8_t, 12> foo3 = ReadOperation::GetValue<std::array<uint8_t, 12>>();
    std::cout << foo3.data() << std::endl;
    
    return 0;
}

But this is just half the truth. The original question was about how to imitate the use of a void pointer. And the solution is: Just use std::any exactly the way you'd use a void pointer.

It's straight forward: just wrap the pointer to your object to std::any, not the object itself. This will prevent it from creating a forwarded instance on the heap.

int main()
{
    std::array<uint8_t, 12> arr { "hello world" };
    std::cout << "Memory location: " << &arr << std::endl;
    
    // The new and better way
    std::any ptr1 = &arr;
    std::array<uint8_t, 12>* foo1 = std::any_cast<std::array<uint8_t, 12>*>(ptr1);
    std::cout << "Memory location: " << foo1 << std::endl;
    
    // The old-school but unsafe way
    void* ptr2 = &arr;
    std::array<uint8_t, 12>* foo2 = static_cast<std::array<uint8_t, 12>*>(ptr2);
    std::cout << "Memory location: " << foo2 << std::endl;  
}

Result: All memory locations should be the same as opposed to the previous example where you'll get a reference/pointer to the instance hold by the std::any value.

And finally, revisiting to the original questions on how to subsitute the void pointer by std::any we end up with:

struct ReadOperation
{
    template <LeafnodeConcept L> 
    static bool visitLeafnode(L *l)
    {
        value = &l->data;
        return false;
    }

    template <class T> 
    static const T GetValue()
    {
        //return *static_cast<T*>(value);
        return *std::any_cast<T*>(value);
    }

    template<class T>
    static const T* GetValueRef()
    {
        // return static_cast<T*>(value);
        return std::any_cast<T*>(value);
    }

  private:
    inline static std::any value = nullptr;
    //inline static void* value = nullptr;
};