10

在许多关于面向数据设计的著作中发挥突出作用的一个特征是,在许多情况下,而不是 AoS(结构数组):

struct C_AoS {
  int    foo;
  double bar;
};

std::vector<C_AoS> cs;
...
std::cout << cs[42].foo << std::endl;

在 SoA(数组结构)中排列数据更有效:

struct C_SoA {
  std::vector<int>    foo;
  std::vector<double> bar;
};

C_SoA cs;
...
std::cout << cs.foo[42] << std::endl;

现在我正在寻找一种解决方案,它允许我在不改变调用接口的情况下在 AoS 和 SoA 之间切换,也就是说,我可以用最少的努力并且没有额外的运行时成本(至少到过度间接的程度),调用例如cs[42].foo;,无论我使用哪种数据排列。

我应该注意,上面的示例语法是理想的情况,这很可能是不可能的,但我也会对近似值非常感兴趣。有接盘侠吗?

4

1 回答 1

8

我将选择这种语法:cs.foo[42]作为单一语法并使用 typedefs 在安排之间切换:

因此,显然C_SoA从您的帖子中可以看出,上述语法有效,我们可以:

typedef C_SoA Arrangement;

Arrangement cs;

为了使用它std::vector<C_AoS>,我们将不得不引入其他东西:

typedef std::vector<C_AoS> AOS;

template<class A, class C, class T>
struct Accessor {
    T operator[](size_t index){
            return arr[index].*pMember;
    }
    T (C::*pMember);
    A& arr;
    Accessor(A& a, T (C::*p)): arr(a), pMember(p){}
};

struct Alt_C_AoS{
    Accessor<AOS, C_AoS, int> foo;
    Accessor<AOS, C_AoS, double> bar;

    AOS aos;
    Alt_C_AoS():foo(aos, &C_AoS::foo), bar(aos, &C_AoS::bar){}
};

现在我们可以拥有:

//Choose just one arrangement
typedef Alt_C_AoS Arrangement;
//typedef C_SoA Arrangement;

Arrangement cs;
...
std::cout << cs.foo[42] << std::endl;

本质上,这转换container dot member indexcontainer index dot member.

于 2015-03-19T10:11:35.743 回答