std :: any

时间:2017-12-08 00:28:07

标签: c++ metaprogramming c++17 c++-standard-library

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

每当从容器中查询对象时,在调用std::any_cast创建任何对象时,将使用完全相同类型的std::make_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_indexstd::type_info来实现目标的解决方法?

编辑:
根据@KerrekSB的要求。下面是这个动态大小的std :: any容器的示例用法,用于创建具有动态属性的类。

#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 ++的静态类型哲学相反。

3 个答案:

答案 0 :(得分:5)

  

是否可以将decltype(mySet)存储为运行时变量

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

这正是您any_cast时必须明确提供类型的原因。

答案 1 :(得分:2)

没有。 C ++不是动态类型语言。即使变量被声明为auto,它的类型在编译时也是固定的 - 它只是为了让你不必自己写出右侧的类型。声明类型依赖于运行时信息的变量是不可能的 - 除非所有可能的类型都有一个公共基类。

大多数情况下,std::any对于这个原因没有用处:当你拥有一组对象并以这种方式擦除它们的类型时,这些对象通常会变得无用。如果你不知道它们是什么,那么你就无法对它们做任何事情。

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

答案 2 :(得分:0)

如果您的操作和/或类型以某种方式可枚举(例如,有限),那么您可以解决此问题。

Here是一些包含any操作的系统的示例。然后,无论何时在any中存储值,操作都会自动写入并存储。

稍后您可以调用any中存储的对象的操作,而不知道该类型是什么。

这需要了解在存储它们之前,您需要对any 的内容执行哪些操作。或者,如果您发现可接受的部分功能,您可以存储它只对存储的可能类型的子集起作用。

您可以将typeindex的地图存储到某个操作中,检查any是否具有与任何键匹配的类型,如果是,则调用该操作,否则,标记错误。< / p>

C ++没有运行时具体化,禁止在产品中附带C ++编译器,编译自定义DLL,然后动态加载它。 (不,不要这样做)但是你可以经常通过各种类型的擦除技术来解决通过具体化解决的问题。