【问题标题】:C++ map key to objectC++ 将键映射到对象
【发布时间】:2018-07-10 05:31:41
【问题描述】:

嗨,有没有一个容器,其中键是类型名,值是 boost 或 std 中的对象/实例?

我想要实现的是每个数据类型都有一个对象池,当我想构造该对象时,我只想通过 Key 获取。我已经有了工作代码,但如果我使用更标准的代码,我会更开心。

目前我有这样的代码:

            template<size_t index, size_t counter, typename T0, typename ...T>
            struct PoolBuilderInternal
            {
                typedef typename boost::mpl::insert<
                    typename PoolBuilderInternal<index - 1, counter + 1, T...>::m
                    , boost::mpl::pair<T0, std::integral_constant<size_t, counter> > >::type m;
            };

            template<size_t counter, typename T0, typename ...T>
            struct PoolBuilderInternal<1, counter, T0, T...>
            {
                typedef typename boost::mpl::map<boost::mpl::pair<T0, std::integral_constant<size_t, counter> > > m;
            };

            template<typename ...T>
            struct Pools
            {
                std::tuple<
                    boost::object_pool<T>...> m_pools;
                typedef typename PoolBuilderInternal<sizeof...(T), 0, T...>::m poolType;

                template<typename T>
                boost::object_pool<T>& GetPool()
                {
                    return std::get< boost::mpl::at<poolType, T>::type::value>(m_pools);
                }
            };

            Pools<int, std::string, int64_t> m_pools;
            m_pools.Get<int>();

编辑:我想要的是 COMPILE-TIME 地图。您可以想象一个 std::tuple 但有些不会被索引 std::get... 访问,而是通过键 (?std::tuple_map)

【问题讨论】:

  • 您可以使用typeid()::hash_code()std::type_index() 来识别类型。
  • 但这些是运行时值...我想在编译时获得正确的对象池。对象池的每种类型都有不同的模板参数,因此此映射对于每个键都有不同类型的不同值
  • 使用 mpl::map 将类型映射到存储类型(定义静态成员的类型)。如果你需要,多个这样的地图,你可以使用一个标签类。
  • 请注意,除非您需要一些语法糖,否则它看起来有点矫枉过正。恕我直言,特征类的简单特化更具可读性。

标签: c++ boost-mpl


【解决方案1】:

如果池中的类型是唯一的,请使用 c++ 14 std::get< T >(std::tuple(s))

#include <iostream>
#include <string>
#include <tuple>

struct A
{
    int value = 17;
};

int main()
{
    auto t = std::make_tuple(1, std::string{"Foo"}, 3.14, A{});
    std::cout << "(" << std::get<int>(t) << ", "
              << std::get<std::string>(t)
              << ", " << std::get<double>(t)
              << ", " << std::get<A>(t).value << ")\n";
}

【讨论】:

    【解决方案2】:

    如果我正确理解了这个问题(我不确定我是否正确),那么您真正想要的是某种类工厂,并且它以各种形式是众所周知的设计模式,因为它允许工厂的用户构造对象,这些对象的构造函数(实际上是类型,当涉及到类层次结构时,通常是类型)是未知的或禁止使用的。

    在此基础上,我谦虚地为您提供以下概念验证代码。请注意,我很匆忙地将它放在一起,它可能不是最佳的。我相信还有更多可能,包括从调用站点将参数传递给相关构造函数到make_string()make_foo()(例如factory [t_string] ("My string")。如果你有兴趣的话,我会在有时间的时候研究一下这篇文章。

    好的,这是你的类工厂。您应该能够将其应用于任何类型,包括增强类型。按照编码,当工厂函数(例如make_string)添加到映射时,当前定义了需要传递给相关对象的任何参数(这可能并不理想)。这些工厂函数也可以/应该是 lambdas。再说一遍,我稍后再补充。

    #include <functional>
    #include <unordered_map>
    #include <variant>
    #include <iostream>
    
    struct Foo
    {
        Foo (int x) : x (x) { }
        int x;
    };
    
    enum ObjectType { t_string, t_foo }; // ...
    using all_possible_types = std::variant <std::string, Foo>;  // ...
    
    static all_possible_types make_string (const std::string& s)
    {
        std::cout << "make_string " << s << "\n";
        return all_possible_types (std::string (s));
    }
    
    static all_possible_types make_foo (int x)
    {
        std::cout << "make_foo " << x << "\n";
        return all_possible_types (Foo (x));
    }
    
    // ...                                            
    
    int main()
    {
        std::unordered_map <ObjectType, std::function <all_possible_types ()>> factory;
    
        factory.insert ({t_string, std::bind (make_string, "Initial string value")});
        factory.insert ({t_foo, std::bind (make_foo, 42)});
        // ...
    
        all_possible_types variant_string = factory [t_string] ();
        std::cout << std::get <std::string> (variant_string) << "\n\n";
    
        all_possible_types variant_foo = factory [t_foo] ();
        std::cout << std::get <Foo> (variant_foo).x << "\n";
    }
    

    输出:

    make_string Initial string value
    Initial string value
    
    make_foo 42
    42
    

    Live demo.

    正如我所说,这现在看起来并不多,但我稍后会改进它。同时,我建议您看一下它,以了解我在这里所做的事情。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-01
      • 1970-01-01
      • 2016-07-04
      • 1970-01-01
      • 2021-08-16
      • 1970-01-01
      • 2019-05-27
      相关资源
      最近更新 更多