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;
};