【问题标题】:Automate repeated code for various types?自动化各种类型的重复代码?
【发布时间】:2021-11-09 16:31:39
【问题描述】:

有什么方法可以自动完成这个

DeserializeComponent<IDComponent>(json, e);
DeserializeComponent<NameComponent>(json, e);
DeserializeComponent<PointLightComponent>(json, e);
// ...

正如您在此处看到的,针对不同类型执行相同的代码,但据我所知,在 C++ 中,您不能将类型存储在 std::vector 中。有什么方法可以让我自动化吗?就像循环在应用程序启动时添加到向量中的组件一样?另外,我想避免 RTTI。

【问题讨论】:

    标签: c++ templates template-meta-programming


    【解决方案1】:

    类型不能存储在变量中。类型仅适用于编译器。甚至 RTTI 也不将类型存储在变量中,而是类型的“名称”。

    我认为您只是想通过不必一遍又一遍地输入DeserializeComponent&lt;&gt;(json, e); 来缩短代码。好吧,您可以通过参数包扩展做到这一点。

    template<typename... Components>
    void DeserializeComponents(json_t& json, e_t& e)
    {
        (DeserializeComponent<Components>(json, e), ...);
    }
    
    // ...
    
    DeserializeComponents<IDComponent, NameComponent, PointLightComponent>(json, e);
    

    神奇之处在于 typename... Components - 它表示 Components 不仅仅是一个类型参数,而是一个类型参数列表 - 和 (DeserializeComponent&lt;Components&gt;(json, e), ...); 表示复制粘贴每个 Components 参数的函数调用,并且将它们与逗号运算符 , 一起加入

    编译器展开模板时,展开后的模板如下所示:

    void DeserializeComponents<IDComponent, NameComponent, PointLightComponent>(json_t& json, e_t& e)
    {
        (
         DeserializeComponent<IDComponent>(json, e),
         DeserializeComponent<NameComponent>(json, e),
         DeserializeComponent<PointLightComponent>(json, e)
        );
    }
    

    【讨论】:

    • 看起来我要使用它并将参数包放入宏中,这样我就可以在任何地方使用它。 :)
    【解决方案2】:

    您可以将类型存储在std::tuple&lt;tag&lt;Ts&gt;...&gt;TypeList&lt;Ts...&gt; 然后使用可变参数模板。

    template <typename T> struct Tag{ using type = T; };
    
    using MyTypes = std::tuple<Tag<IDComponent>, Tag<NameComponent>/*, ...*/>;
    
    // And then do something like
    void foo()
    {
        // ...
        apply([&](auto tag){ DeserializeComponent<typename decltype(tag)::type>(json, e) },
             MyTypes{});
    }
    
    

    【讨论】:

    • 请注意,类型只能在编译时以这种方式“存储” - MyTypes 不是变量。
    【解决方案3】:

    可以也可以通过将函数调用包装到 DeserializeComponents&lt;T&gt;(...) 内的仿函数来实现,该仿函数使用通过 parameter pack 提供给它的不同类型递归调用自身。

    // Other stuff...
    
    // The code below works only with compilers that support C++11 or above
    #include <utility>
    
    template <typename T, typename ...Ts>
    struct deserialize {
        template <typename A, typename B>
        void operator()(A&& a, B&& b) const {
            DeserializeComponent<T>(std::forward<A>(a), std::forward<B>(b));
            deserialize<Ts...>{}(std::forward<A>(a), std::forward<B>(b));
        }
    };
    
    template <typename T>
    struct deserialize<T> {
        template <typename A, typename B>
        void operator()(A&& a, B&& b) const {
            DeserializeComponent<T>(std::forward<A>(a), std::forward<B>(b));
        }
    };
    
    // Other stuff...
    

    那么你就可以这样做了:

    deserialize<IDComponent, NameComponent, PointLightComponent/*, ...*/>{}(json, e);
    

    【讨论】:

      猜你喜欢
      • 2015-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-11
      • 2019-04-01
      • 2021-09-11
      相关资源
      最近更新 更多