【问题标题】:How to specify degenerate dimension of boost multi_array at runtime?如何在运行时指定 boost multi_array 的退化维度?
【发布时间】:2012-01-18 22:14:37
【问题描述】:

我有一个 3D multi_array,我想使用运行时指定的维度制作 2D 切片。我知道退化维度的索引和要在该退化维度中提取的切片的索引。目前,丑陋的解决方法如下所示:

if (0 == degenerate_dimension)
{
    Slice slice = input_array[boost::indices[slice_index][range()][range()]];
}
else if (1 == degenerate_dimension)
{
    Slice slice = input_array[boost::indices[range()][slice_index][range()]];
}
else if (2 == degenerate_dimension)
{
    Slice slice = input_array[boost::indices[range()][range()][slice_index]];
}

有没有更漂亮的方式来构造 index_gen 对象? 类似的东西:

var slicer;
for(int i = 0; i < 3; ++i) {
    if (degenerate_dimension == i)
        slicer = boost::indices[slice_index];
    else
        slicer = boost::indices[range()];
}
Slice slice = input_array[slicer];

似乎每次对 boost::indices::operator[] 的后续调用都会根据维度(即先前调用的数量)返回不同的类型,因此无法使用可以保存临时 index_gen 的单个变量对象。

【问题讨论】:

  • +1 用于使用理智的多维数组的明确问题,而不是 C 的东西! :)

标签: c++ boost boost-multi-array


【解决方案1】:

您要做的是将变量从运行时移动到编译时。这只能通过if else 语句链或switch 语句链来完成。

一个简化的例子

// print a compile time int
template< int I >
void printer( void )
{
   std::cout << I << '\n';
}

// print a run time int
void printer( int i )
{
   // translate a runtime int to a compile time int
   switch( i )
   {
      case 1: printer<1>(); break;
      case 2: printer<2>(); break;
      case 3: printer<3>(); break;
      case 4: printer<4>(); break;
      default: throw std::logic_error( "not implemented" );
   }
}

// compile time ints
enum{ enum_i = 2 };
const int const_i = 3;
constexpr i constexper_i( void ) { return 4; }

// run time ints
extern int func_i( void ); // { return 5; }
extern int global_i; // = 6

int main()
{
   int local_i = 7;
   const int local_const_i = 8;

   printer<enum_i>();
   printer<const_i>();
   printer<constexpr_i()>();
   //printer<func_i()>();
   //printer<global_i>();
   //printer<local_i>();
   printer<local_const_i>();

   printer( enum_i );
   printer( const_i );
   printer( constexpr_i() );
   printer( func_i()      ); // throws an exception
   printer( global_i      ); // throws an exception
   printer( local_i       ); // throws an exception
   printer( local_const_i ); // throws an exception
}

【讨论】:

    【解决方案2】:

    请试试这个。 Сode 有一个缺点 - 它指的是在 boost::detail:: multi_array 命名空间中声明的 range_array 变量。

    #include <boost/multi_array.hpp>                                                                                                                              
    
    typedef boost::multi_array<double, 3> array_type;                                                                                                             
    typedef boost::multi_array_types::index_gen::gen_type<2,3>::type index_gen_type;                                                                                   
    typedef boost::multi_array_types::index_range range;                                                                                                          
    
    index_gen_type                                                                                                                                                     
    func(int degenerate_dimension, int slice_index)                                                                                                               
    {                                                                                                                                                             
        index_gen_type slicer;                                                                                                                                         
        int i;                                                                                                                                                    
        for(int i = 0; i < 3; ++i) {                                                                                                                              
            if (degenerate_dimension == i)                                                                                                                        
                slicer.ranges_[i] = range(slice_index);                                                                                                           
            else                                                                                                                                                  
                slicer.ranges_[i] = range();                                                                                                                      
        }                                                                                                                                                         
        return slicer;                                                                                                                                            
    }                                                                                                                                                             
    
    int main(int argc, char **argv)                                                                                                                               
    {                                                                                                                                                             
        array_type myarray(boost::extents[3][3][3]);                                                                                                              
        array_type::array_view<2>::type myview = myarray[ func(2, 1) ];                                                                                           
        return 0;                                                                                                                                                 
    }
    

    【讨论】:

    • 这很棒而且很有效。很抱歉,我在赏金仍在进行时错过了它,所以我将通过投票给你在个人资料页面上获得的所有 18 个答案来给你 100 名声望。虽然这是对评级系统的一种破解,但我不知道有其他方法可以做到这一点。
    • 您是在阅读 multi_array 的源代码时想到的,还是从文档中获得的?
    • 非常感谢您的声誉 :) 很高兴听到此代码对您有所帮助。为了找到解决方案,我只使用了 multi_array 的源代码并应用了 C++ 知识。
    • @alexander 在::detail 中使用某些东西通常是“错误的”吗?比如,出于某种原因我应该避免使用它吗?
    • @David Doria,我认为 ::detail 命名空间中的内容是用于 multi_array 实现的,并且可以在 boost 版本之间更改,恕不另行通知。虽然 multi_array 接口内部的东西在 boost 版本之间保持稳定。因此,如果您使用 ::detail 中的某些内容,请准备好您的代码可能会被破坏。
    猜你喜欢
    • 2011-09-20
    • 2017-01-31
    • 1970-01-01
    • 2012-04-05
    • 1970-01-01
    • 2014-07-08
    • 2020-03-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多