问题
I have a 3D multi_array and I would like to make 2D slices using dimensions specified at runtime. I know the index of degenerate dimension and the index of a slice that I want to extract in that degenerate dimension. Currently the ugly workaround looks like that:
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]];
}
Is there a more beautiful way to construct index_gen object? Something like that:
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];
It seems each subsequent call to boost::indices::operator[] returns a different type depending on the dimensionality (i.e. number of previous calls), so there's no way to use a single variable, that can hold the temporary index_gen object.
回答1:
Please, try this. Сode has one disadvantage - it refers to ranges_ array variable declared at boost::detail:: multi_array namespace.
#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;
}
回答2:
What you're trying to do is move a variable from run time to compile time. This can only be done with a chain of if else
statements or a switch
statement.
A simplified example
// 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
}
来源:https://stackoverflow.com/questions/8482445/how-to-specify-degenerate-dimension-of-boost-multi-array-at-runtime