【问题标题】:Heterogeneous sequence generator异构序列生成器
【发布时间】:2013-07-29 21:34:28
【问题描述】:

继续这个话题Variadic template heterogeneous container,我想问以下问题。假设我们有几个类,其中两个成员是动态数组。现在假设有这些类的对象序列,它们被包装在异构容器中。在这个序列中,数组成员之一是“输出”向量,另一个数组成员是“输入”向量,它是指向来自前一个对象的适当输出数组的指针。这个序列被实现为可变参数模板类:

//Classes, objects which are members of the sequence
template<int NumberElements>
struct A 
{
    A() : output(new float[NumberElements]){}//allocate output
    ~A(){delete[] output;}
    float *input;//input vector - pointer to output vector from preceding object of sequence 
    float *output;// output vector (size - NumberElements) of current member of sequence
};   
template<int NumberElements> 
struct B 
{
    B() : output(new float[NumberElements]){}//allocate output
     ~B(){delete[] output;}
    float *input;
    float *output;
};
template<int NumberElements>    
struct C 
{
    C() : output(new float[NumberElements]){}//allocate output
    ~C(){delete[] output;}
    float *input;
    float *output;
};

//Container
template<typename...Arg>
struct HeterogenousContainer
{
    HeterogenousContainer();//Do something to setup the sequence
    std::tuple<Arg...> elements;

};

如何为输出向量正确分配内存(通过new/malloc),并设置输入指针指向前面的输出向量?比如我写下一段代码:

HeterogenousContainer<A<5>, B<7>, C<9>> sequence;

我希望序列的第一个成员的 inputnullptr,第二个成员的 input - 指向 output 从一开始等等,如何正确实现?

【问题讨论】:

  • 为什么要在一个容器内构造一个链表来提供对其元素的各种(包括随机)访问?
  • 假设对元素的访问是连续的——在上面的例子中是从 A 到 C

标签: c++ c++11 metaprogramming


【解决方案1】:

首先,如果可以避免的话,不要乱用手动(取消)分配。对于一个简单的数组,您可以:

#include <array>
#include <tuple>

template<int NumberElements>
struct A 
{
    float *input;
    std::array<float, NumberElements> output;
};

您只需要向下递归元组,并专门处理终止情况。因为 first 元素是你的特例,所以我倒着做。

namespace detail {
    template <int N> struct Connector;

    template <>
    struct Connector<0> {
        template <typename... TL> static void connect(std::tuple<TL...> &t) {
            std::get<0>(t).input = nullptr;
        }
    };

    template <int N> struct Connector {
        template <typename... TL> static void connect(std::tuple<TL...> &t) {
            std::get<N>(t).input = &std::get<N-1>(t).output.front();
            Connector<N-1>::connect(t);
        }
    };

    template <typename... TL> void connect(std::tuple<TL...> &t) {
        Connector<sizeof...(TL)-1>::connect(t);
    }
}

并像这样使用它:

template <typename... Arg> struct HeterogenousContainer {
    std::tuple<Arg...> elements;

    HeterogenousContainer() { detail::connect(elements); }
};

【讨论】:

  • 是否可以将 std::array 对齐 16 字节以用于 SSE 内在函数?
  • 不是直接的。要么将 std::array 包装在处理对齐的东西中(或使用编译器特定的属性 - 你没有说你正在使用哪个编译器),或者切换到 std::unique_ptr 和合适的分配器。不过,这确实是一个单独的问题。
【解决方案2】:

Useless'answer(没有双关语)的启发,我想出了这个:

template<typename...Arg>
struct HeterogenousContainer
{
    std::tuple<Arg...> elements;

    void init(std::integral_constant<std::size_t, 0>)
    {
        std::get<0>(elements).input = nullptr;
    }

    template < std::size_t index = sizeof...(Arg)-1 >
    void init(std::integral_constant<std::size_t, index> = {})
    {
        std::get<index>(elements).input = std::get<index-1>(elements).output;
        init(std::integral_constant<std::size_t, index-1>{});
    }

    HeterogenousContainer()
        : elements{}
    {
        init();
    }
};

【讨论】:

  • “in”和“out”在我的示例中表示“输入”和“输出”?
  • @gorill 哎呀,是的。我为编译测试简化了您的示例;)
  • 语法-elements{}和elements()有区别吗?两者都编译得很好
  • @gorill 在这种情况下,不。两者都将调用tuple 的default-ctor,它将对其元素进行值初始化。这也意味着严格来说,std::get&lt;0&gt;(elements).input = nullptr; 这行应该是不必要的。
猜你喜欢
  • 2014-02-11
  • 2022-11-05
  • 2012-12-19
  • 1970-01-01
  • 2011-08-25
  • 1970-01-01
  • 2021-05-07
  • 2021-08-11
  • 1970-01-01
相关资源
最近更新 更多