std::any 的存储对象类型的可能性

Possibility of store object type for std::any

在c++17中我们有std::any,它在内存中存储可变类型的对象。好的部分是我可以创建一个 std::any 的向量来模拟任意类型对象的容器。

每当从容器中查询对象时,都会使用 std::any_cast with the exact same type when calling std::make_any 创建 any 对象。这是我如何实现这一目标的片段

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

问题如下: 是否可以将 decltype(mySet) 存储为 运行 时间变量,以便我们可以在 any_cast 中使用它来自动解析我们想要获取的类型?我知道您可能无法将类型存储在内存中,因为它是编译时变量,但是是否有使用 std::type_index or std::type_info 来实现目标的解决方法?

编辑:
根据@KerrekSB 的要求。这是使用 std::any 的动态大小容器创建具有动态属性的 class 的示例用法。

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

感谢大家让我知道这是不可能的,因为它与 C++ 的静态类型哲学形成对比。

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

没有。 C++ 是一种静态类型语言。无法在运行时确定类型。每个表达式的类型,例如将 return 存储在 any 中的值的函数的 return 值,必须在 编译时 知道].

这就是为什么在 any_cast 时必须明确提供类型的原因。

没有。 C++ 不是动态类型语言。即使声明了一个变量 auto,它的类型在编译时也是固定的——它只是让你不必自己写出右边的类型。声明一个类型取决于运行时信息的变量是不可能的——除非所有可能的类型都有一个共同的基础 class.

大多数时候,std::any 没有用正是因为这个原因:当您有一个对象集合并以这种方式擦除它们的类型时,这些对象通常会变得无用。如果您不知道它们是什么,那么您将无能为力。

您确定不想改用 std::variant 吗?还是std::tuple?还是模板?

如果你的操作 and/or 类型在某些方面是可枚举的(例如有限的),那么你可以解决这个问题。

是一些系统将 any 与操作打包在一起的示例。然后,每当您在 any 中存储一个值时,操作就会自动写入并存储。

稍后您可以在不知道类型是什么的情况下调用存储在 any 中的对象上的操作。

这确实需要知道 在存储 any 的内容之前,您需要能够对其执行哪些操作。或者,如果您发现部分函数可以接受,则可以存储它只对存储的可能类型的子集起作用。

您可以存储从 typeindex 到某个操作的映射,检查 any 是否具有与任何键匹配的类型,如果是,则调用该操作,如果不是,则标记错误.

C++ 没有运行时具体化,除非随产品一起提供 C++ 编译器,编译自定义 DLL,然后动态加载它。 (不,不要这样做)但是您通常可以通过各种类型的擦除技术解决原本可以通过具体化解决的问题。