2016-04-08 34 views
2

Aşağıdaki kodda ExtractSubArray işlevi tamamen geneldir, ExtractSubArrayCornerAndExtent ise kod yazılırken (RangeType argümanlarının sırasını oluşturmak için) boyutsallık bilgisini gerektirir.) Olası boyutlar sabit bir dizi gerektirecek gibi SFINAE da rahatsız edici olabilir, her boyut için farklı bir işlev (kullanımı olmadan (genel bir ExtractSubArrayCornerAndExtent yazmak için herhangi bir yolu yoktur., Genel olarakÇalışma zamanında multi_array :: index_gen nasıl oluşturulur

#include <boost/multi_array.hpp> 

template <unsigned int Dimension> 
boost::multi_array<double, Dimension> ExtractSubArray(const boost::multi_array<double, Dimension>& array, const typename boost::detail::multi_array::index_gen<Dimension, Dimension>& indices) 
{ 
    using ArrayType = boost::multi_array<double, Dimension>; 
    using IndexType = boost::array<double, Dimension>; 

    typename ArrayType::template const_array_view<Dimension>::type view = array[indices]; 

    IndexType subArraySize; 
    for(size_t dim = 0 ; dim < Dimension; ++dim) { 
     subArraySize[dim] = indices.ranges_[dim].finish_ - indices.ranges_[dim].start_; 
    } 

    ArrayType subArray = view; 

    return subArray; 
} 

template <unsigned int Dimension> 
boost::multi_array<double, Dimension> ExtractSubArrayCornerAndExtent(const boost::multi_array<double, Dimension>& array, const boost::array<double, Dimension>& corner, 
           const boost::array<double, Dimension>& subarraySize) 
{ 
    using ArrayType = boost::multi_array<double, Dimension>; 
    using RangeType = typename ArrayType::index_range; 

    // Here I have assumed Dimension=3 to produce the second argument. How do you construct this second argument when you don't know Dimension ahead of time. 
    return ExtractSubArray<Dimension>(array, boost::indices[RangeType(corner[0],subarraySize[0])][RangeType(corner[1],subarraySize[1])][RangeType(corner[2],subarraySize[2])]); 
} 

int main() 
{ 
    using ArrayType = boost::multi_array<double, 3>; 
    using IndexType = boost::array<double, 3>; 

    ArrayType myArray(IndexType({{3,3,3}})); 

    std::vector<double> data(9); 
    for(size_t i = 0; i < data.size(); ++i) { 
     data[i] = i; 
    } 

    boost::detail::multi_array::index_gen<3,3> indices = boost::indices[ArrayType::index_range(0,1)][ArrayType::index_range(0,1)][ArrayType::index_range(0,1)]; 

    ArrayType subArray = ExtractSubArray<3>(myArray, indices); 

    IndexType corner = {0,0,0}; 
    IndexType subarraySize = {1,1,1}; 
    ArrayType subArray2 = ExtractSubArrayCornerAndExtent<3>(myArray, corner, subarraySize); 

    return 0; 
} 

cevap

2

Derleme zamanlı yineleme yineleme ile uygulanacak olan bir özyinelemeli şablonu kullanarak dizin nesnesi oluşturabilir böyle bir şey bakabilirsiniz.:.

#include <boost/multi_array.hpp> 

template <typename T, size_t Dimension> 
boost::multi_array<T, Dimension> ExtractSubArray(
    const boost::multi_array<T, Dimension>& array, 
    const typename boost::detail::multi_array::index_gen<Dimension, Dimension>& indices) 
{ 
    using ArrayType = boost::multi_array<T, Dimension>; 
    using IndexType = boost::array<size_t, Dimension>; 

    typename ArrayType::template const_array_view<Dimension>::type view = array[indices]; 

    IndexType subArraySize; 
    for(size_t dim = 0 ; dim < Dimension; ++dim) { 
     subArraySize[dim] = indices.ranges_[dim].finish_ - indices.ranges_[dim].start_; 
    } 

    ArrayType subArray = view; 

    return subArray; 
} 

// Helper functor to build indices. 
template<typename RangeArrayType, size_t Dimension> 
struct IndicesBuilder { 
    // Recursively invoke the functor for the next lowest dimension and 
    // add the next range. 
    static auto build(const RangeArrayType& range) 
     -> decltype(IndicesBuilder<RangeArrayType, Dimension - 1>::build(range)[range[Dimension - 1]]) { 
     return IndicesBuilder<RangeArrayType, Dimension - 1>::build(range)[range[Dimension - 1]]; 
    } 
}; 

// Helper functor specialization to terminate recursion. 
template<typename RangeArrayType> 
struct IndicesBuilder<RangeArrayType, 1> { 
    static auto build(const RangeArrayType& range) 
     -> decltype(boost::indices[range[0]]) { 
     return boost::indices[range[0]]; 
    } 
}; 

template <typename T, size_t Dimension> 
boost::multi_array<T, Dimension> ExtractSubArrayCornerAndExtent(
    const boost::multi_array<T, Dimension>& array, 
    const boost::array<size_t, Dimension>& corner, 
    const boost::array<size_t, Dimension>& subarraySize) 
{ 
    using ArrayType = boost::multi_array<T, Dimension>; 
    using RangeType = typename ArrayType::index_range; 

    // Build a random-access container with the ranges. 
    std::vector<RangeType> range; 
    for (size_t i = 0; i < Dimension; ++i) 
     range.push_back(RangeType(corner[i], corner[i] + subarraySize[i])); 

    // Use the helper functor to build the index object. 
    const auto index = IndicesBuilder<decltype(range), Dimension>::build(range); 

    return ExtractSubArray<T, Dimension>(array, index); 
} 

int main() { 
    using ArrayType = boost::multi_array<double, 3>; 
    using IndexType = boost::array<size_t, 3>; 

    ArrayType myArray(IndexType({{3,3,3}})); 

    IndexType corner = {0,0,0}; 
    IndexType subarraySize = {1,1,1}; 
    ArrayType subArray2 = ExtractSubArrayCornerAndExtent(myArray, corner, subarraySize); 

    return 0; 
}; 

kodunuzu eklenmesi oluşturması için bir statik işlevi vardır IndicesBuilder şablon yapı olduğunu indeks nesnesinin boyutu: Bu statik fonksiyon kendini çağırır (farklı t ile) tüm boyutları oluşturmak için emplate argümanlar). Özyineleme, ilk boyutu döndüren IndicesBuilder uzmanlaşmasıyla sonlandırılır. Geri dönüş türlerini takip et!

Bu kodu ciddi hatalar olmadan derledim ve çalıştırdım, ancak daha fazla hata yapmadığım için daha fazla sınama yapmadım. Genel yaklaşım olsa da, çalışmalıdır.

+1

Doğru şekilde anlarsam, 'ExtractSubArrayCornerAndExtent' işlevinde, range.push_back (RangeType (köşe [i], köşe [i] + subarraySize [i])); – astroboylrx

+0

@astroboylrx Haklı olduğunu düşünüyorum. Düzeltme için teşekkürler. – rhashimoto

İlgili konular