Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Possibility of store object type for std::any

In c++17 we have the std::any which stores variable type of object in memory. Good part is I can create a vector of std::any to simulate a container for arbitrary type of object.

Whenever to query back the object from the container one will use std::any_cast with the exact same type when calling std::make_any to create the any object. Here is the snippet of how I achieve this

#include <any>
#include <iostream>
#include <unordered_map>
#include <vector>
#include <set>

int main()
{
    /* create some objects */
    std::set<int> mySet = { 1, 2, 3 };
    std::vector<int> myVec = { 3, 4, 5 };
    std::unordered_map<int, std::vector<int>> myHash = { std::make_pair(1, myVec) };
    /* create any store */
    std::vector<std::any> anyStore;
    anyStore.push_back(std::make_any<decltype(mySet)>(mySet));
    anyStore.push_back(std::make_any<decltype(myVec)>(myVec));
    anyStore.push_back(std::make_any<decltype(myHash)>(myHash));
    /* get object back */
    auto newSet = std::any_cast<decltype(mySet)>(anyStore[0]);
    auto newVec = std::any_cast<decltype(myVec)>(anyStore[1]);
    auto newHash = std::any_cast<decltype(myHash)>(anyStore[2]);

    /* Question is can we store the decltype(mySet) in memory so that 
     * it can be read back while query from the vector to do any_cast?
     */

    return 0;
}

The question is as follows: Is it possible to store the decltype(mySet) as run time variable so that we can use it in any_cast to auto resolve the type we want to get? I know probably you cannot store the type in memory since it is compile time variable, but is there workaround like using std::type_index or std::type_info to achieve goal?

Edit:
Per @KerrekSB 's request. Here is an example usage of this dynamic sized container of std::any to create a class with dynamic properties.

#include <any>
#include <iostream>
#include <unordered_map>
#include <vector>
#include <set>
#include <string>

class FooWithDynamic
{
public:
    FooWithDynamic() = default;

    template <class T>
    void RegisterProperty(const std::string &key, const T &obj)
    {
        m_store.emplace(key, std::make_any<T>(obj));
    }

    template <class T>
    T GetProperty(const std::string &key)
    {
        if (m_store.find(key) == m_store.end())
            throw;
        return std::any_cast<T>(m_store[key]);
    }
private:
    std::unordered_map<std::string, std::any> m_store;
};

int main()
{
    /* create some objects */
    FooWithDynamic foo;
    foo.RegisterProperty("mySet", std::set<int>{ 1, 2, 3 });
    foo.RegisterProperty("myVec", std::vector<int>{ 1, 2, 3 });
    foo.RegisterProperty("myHash", std::unordered_map<int, int>{ std::make_pair(1, 2) });
    /* query back object */
    auto mySet = foo.GetProperty<std::set<int>>("mySet");
    auto myVec = foo.GetProperty<std::vector<int>>("myVec");
    auto myHash = foo.GetProperty<std::unordered_map<int, int>>("myHash");
    return 0;
}

Thanks everyone to let me know this is not possible because it is in contrast of C++'s static typed philosophy.

like image 673
yc2986 Avatar asked Dec 08 '17 00:12

yc2986


2 Answers

Is it possible to store the decltype(mySet) as run time variable

No. C++ is a statically typed language. Types cannot be determined at runtime. The type of every expression, like the return value of a function that would return the value stored in the any, must be known at compile time.

That's precisely why you have to supply the type explicitly when you any_cast.

like image 197
Nicol Bolas Avatar answered Sep 30 '22 18:09

Nicol Bolas


No. C++ is not a dynamically typed language. Even when a variable is declared auto, its type is fixed at compile time---it just makes it so that you don't have to write out the type of the right-hand side yourself. It is impossible to declare a variable whose type depends on runtime information---unless all the possible types have a common base class.

Most of the time, std::any is not useful for precisely this reason: when you have a collection of objects and you erase their types in this way, those objects usually become useless. If you don't know what they are, then you can't do anything with them.

Are you sure you don't want to use std::variant instead? Or std::tuple? Or templates?

like image 29
Brian Bi Avatar answered Sep 30 '22 16:09

Brian Bi