2017-02-08 23 views
2

是否有可能創建一個「稀疏」可變長度二維數組,只使用可變參數模板和std :: array?由於稀疏,我的意思是每行可能有不定數量的列。使用可變參數模板創建具有可變列寬度的二維數組?

理想情況下,我想實例化類似VariableLengthTable<int,2,4,3>()的東西,並讓它創建一個映射到像{{0,1}, {0,1,2,3}, {0,1,2}}之類的數組的數組。我已經看過SO帖子處理variadic模板來創建多維數組,但它們都是對稱的。

注意,我限於零成本的抽象(例如標準::陣列),爲我正在與一個非常存儲器收縮應用程序的工作。

+1

我不太確定你需要一個可變模板來做到這一點。不是'std :: vector >'或者至少是'std :: array ,N>'一個選項? –

+0

我正在尋找零成本或非常非常低的成本。 'std :: vector'對於我們的應用程序來說太大了。 –

回答

3

是的,原則上這應該是可能的。這是一個有點讓你開始:

template <class T, std::size_t... Dim> 
using VariableLengthTable = std::tuple<std::array<T, Dim>...>; 

這是std::array,每個具有由模板參數之一指定的長度的元組。

注意,由於一個std::array的長度是它的類型的一部分,第一尺寸不能是一個數組,因爲它的成員需要不同的類型。但是,std::tuple很好地工作。只要你願意使用std::get<i>而不是[i],並且將自己限制在編譯時間i s,那麼你應該很好。

如果編譯時i是不夠的,你有兩個選擇:

一個,使用VariableLengthTable如上並添加運行到編譯時轉換。從概念上講,這樣的事情switch

T& get(std::size_t x, std::size_t y) 
{ 
    switch (x) { 
    case 0: return std::get<0>(varLenTable)[y]; 
    case 1: return std::get<1>(varLenTable)[y]; 
    case 2: return std::get<2>(varLenTable)[y]; 
    // and so on 
    } 
} 

在現實中,你可能需要編寫這個使用遞歸或繼承,以避免編譯時出界外的訪問。 Boost.Preprocessor可能有幫助。

兩個,將所有數據存儲在一個順序緩衝區中並在運行時將其索引到它。類似這樣的:

template <class T, std::size_t... Dim> 
class VariableLengthTable 
{ 
    static const std::array<std::size_t, sizeof...(Dim)> dims = {{ Dim... }}; 

    static const std::array<std::size_t, sizeof...(Dim)> cumulDims = [](){ 
    std::array<std::size_t, sizeof...(Dim)> result; 
    result[0] = 0; 
    for (std::size_t idx = 1; idx < sizeof...(Dim); ++idx) { 
     result[idx] = result[idx - 1] + dims[idx]; 
    } 
    return result; 
    }(); 

    std::array<T, cumulDims[sizeof...(Dim) - 1] + dims[sizeof...(Dim) - 1]> data; 

public: 
    T& get(std::size_t x, std::size_t y) 
    { 
    return data[cumulDims[x] + y]; 
    } 
}; 

上面的代碼是顯示原理,不保證按原樣編譯。

+0

謝謝,這可能正是我要找的。我對元組不熟悉。我會試一試! –

+0

經進一步檢查,我不認爲我將能夠使用這在我是因爲'的std :: tuple'的限制的應用程序編譯時'i's。這是一個很酷的解決方案,但不幸的是它不能在運行時在功能上與數組數組相同。我想我可以在表單中添加一個模板函數來接入小區'得到(Y)',但在空間受限的應用,似乎並不理想。 –

+0

@WilliamMoy我已經添加了兩種方法來支持運行時索引。 – Angew