2016-04-08 16 views
2

ExtractSubArray関数は完全に汎用ですが、ExtractSubArrayCornerAndExtentはコードが書き込まれたときの次元性(RangeType引数のシーケンスを構築する)を必要とします。 )迷惑だろうだけでなく、可能な寸法の固定セットが必要と思われる(次元ごとに異なる機能を使用するSFINAEなし(ジェネリックExtractSubArrayCornerAndExtentを書くためにどのような方法があります。一般的に実行時にmulti_array :: index_genを作成する方法

#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; 
} 

答えて

2

コンパイル時反復再帰で実装する必要がありますが、再帰的なテンプレートを使用してインデックスオブジェクトを構築することができますそれはこのようなものに見えることができます。あなたのコードに加えて、1つを構築するために、静的な機能を持っているIndicesBuilderテンプレートの構造体である

#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; 
}; 

をその静的関数はそれ自身を呼び出します(異なるt emplate引数)を使用してすべてのディメンションを作成します。再帰は、最初の次元を返すIndicesBuilderの特殊化によって終了します。末尾の戻り値の型のためのHooray!

私はこのコードを致命的なエラーなしにコンパイルして実行しましたが、それ以上のテストは行っていないため、マイナーなバグがある可能性があります。しかし、一般的なアプローチはうまくいくはずです。

+1

私が正しく理解していれば、関数ExtractSubArrayCornerAndExtentではrange.push_back(RangeType(corner [i]、corner [i] + subarraySize [i])); – astroboylrx

+0

@astroboylrx私はあなたが正しいと思います。訂正してくれてありがとう。 – rhashimoto

関連する問題