2012-10-15 44 views
2

我的問題涉及到一個問題我以前問一個一維數組:多維數組的初始化使用索引招

for loop elimination

可有人請幫助我延長使用索引竅門多的二維陣列,諸如在本例中:

template<unsigned...> struct indices 
{ 
}; 

template<unsigned M, unsigned... Is> struct indices_gen 
    : indices_gen<M - 1, M - 1, Is...> 
{ 
}; 

template<unsigned... Is> struct indices_gen<0, Is...> : indices<Is...> 
{ 
}; 

template <typename T> 
struct example 
{ 
    template<typename ...U, typename 
    = typename std::enable_if<all_of<std::is_same<U, T>...>::value>::type> 
    example(U... args) 
    { 
    static_assert(3 * 2 == sizeof...(U), 
     "wrong number of arguments in assignment"); 
    assign(indices_gen<M * N>(), args...); 
    } 

    template<size_type... Is, class... U> 
    void assign(indices<Is...>, U... args) 
    { 
    [](...){}(((&array[0][0])[Is] = args)...); 
    } 

    T array[3][2]; 
}; 

int main() 
{ 
    example<int> ex(1, 2, 3, 4, 5, 6); 
    return 0; 
} 

目前我取決於要求,即陣列是連續的,但我想分配使用對array索引,而不只是一個單一的指數(理論值的是我能夠支持數組以外的類型,特別是覆蓋operator[])的類型。如果我使用2個參數包進行賦值,我只會在索引(0,0),(1,1),...處分配參數包,如果參數包的長度不相同, array不同(如在示例中)。

回答

4

這可以通過更改訪問數組的代碼而不是索引代更容易。你基本上想要的是一維到二維的訪問映射。

通常情況下,人們需要它周圍(2D到1D)的另一種方式,當他們實現一個二維數組在一維數組方面†

template<class T, unsigned M, unsigned N> 
struct md_array{ 
    T elems[M * N]; // same layout as 'T elems[M][N];' 
}; 

的公式得到1D指數i從2D索引(x,y)然後是i == x * N + y。我們可以(通過M == 2N == 3)解釋這一點,如果我們從上面的二維數組想象我們1D elems

0, 1, 2, 3, 4, 5 // indices (i) 
[a, b, c, d, e, f] 
v // we want them as M (2) packs of N (3) elements 
0, 1, 2 0, 1, 2 // element indices (y) 
[a, b, c] [d, e, f] 
\___0___/ \___1___/ // pack indices (x) 
v // fusing the packs back together, we can see that we have 
    // a constant offset for the packs, which is the N (3) times x 
0*3+0, 0*3+1, 0*3+2, 1*3+0, 1*3+1, 1*3+2 
[ a,  b,  c,  d,  e,  f ] 

因此,我們得到i == x * N + y。我們現在需要解決這個公式不是爲i而是爲xy。對於x,這是相當容易的(使用數學符號):

i = x * N + y | -y 
i - y = x * N | *(1/N) 
i - y 
----- = x 
    N 

所以x == (i - y)/N。現在,可悲的是,我不知道如何使用純數學來解決這個問題,但我們並不需要這個。看一下元素索引,我們可以看到它們圍繞着N,這可以使用模運算符很容易地完成。因此,y == i % N

現在,我們就可以實現,需要一個線性指數i,並返回在解決(x, y)從該元素的方法:

template<unsigned I> 
T& get(){ constexpr auto y = I % 3; return array[(I-y)/3][y]; } 

和概括是:

template<unsigned I> 
T& get(){ constexpr auto y = I % N, x = (I-y)/N; return array[x][y]; } 

使用constexpr保證所有的計算都是在編譯時完成的。 現在,你可以簡單地寫assign如下:

template<unsigned... Is, class... U> 
void assign(indices<Is...>, U... args) 
{ 
    [](...){}((get<Is>() = args)...); 
} 

證明完畢(Live example.


†現在,你可以通過實際實現二維數組作爲一維數組做出對自己更容易些。:)這種方式,你可以直向前使用(array[Is] = args)...和其他情況下使用不會映射一個簡單的存取功能:

T& get(unsigned x, unsigned y){ return array[x * N + y]; } 

Live example.

+0

但我認爲,更好的將是有序的笛卡爾發電機對。 – user1095108