1<?xml version='1.0' encoding="ISO-Latin-1" ?> 2<!DOCTYPE article 3 PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" 4 "http://www.oasis-open.org/docbook/xml/4.0/docbookx.dtd" [ 5 <!ENTITY concepts SYSTEM "MultiArray.xml"> 6 <!ENTITY multi_array SYSTEM "multi_array.xml"> 7 <!ENTITY multi_array_ref SYSTEM "multi_array_ref.xml"> 8 <!ENTITY const_multi_array_ref SYSTEM "const_multi_array_ref.xml"> 9]> 10 11<article> 12 <articleinfo> 13 <title>Boost.MultiArray Reference Manual</title> 14 <author> 15 <surname>Garcia</surname><firstname>Ronald</firstname> 16 <affiliation> 17 <orgname>Indiana University</orgname> 18 <orgdiv>Open Systems Lab</orgdiv> 19 </affiliation> 20 </author> 21 <orgname>BOOST</orgname> 22 <copyright> 23 <year>2002</year> 24 <holder>The Trustees of Indiana University</holder> 25 </copyright> 26 </articleinfo> 27 28 29<para>Boost.MultiArray is composed of several components. 30The MultiArray concept defines a generic interface to multidimensional 31containers. 32<literal>multi_array</literal> is a general purpose container class 33that models MultiArray. <literal>multi_array_ref</literal> 34and <literal>const_multi_array_ref</literal> are adapter 35classes. Using them, 36you can manipulate any block of contiguous data as though it were a 37<literal>multi_array</literal>. 38<literal>const_multi_array_ref</literal> differs from 39<literal>multi_array_ref</literal> in that its elements cannot 40be modified through its interface. Finally, several auxiliary classes are used 41to create and specialize arrays and some global objects are defined as 42part of the library interface.</para> 43 44<sect1 id="synopsis"> 45<title>Library Synopsis</title> 46 <para>To use Boost.MultiArray, you must include the header 47<filename>boost/multi_array.hpp</filename> in your source. This file 48brings the following declarations into scope:</para> 49<programlisting> 50<![CDATA[namespace boost { 51 52 namespace multi_array_types { 53 typedef *unspecified* index; 54 typedef *unspecified* size_type; 55 typedef *unspecified* difference_type; 56 typedef *unspecified* index_range; 57 typedef *unspecified* extent_range; 58 typedef *unspecified* index_gen; 59 typedef *unspecified* extent_gen; 60 } 61 62 template <typename ValueType, 63 std::size_t NumDims, 64 typename Allocator = std::allocator<ValueType> > 65 class multi_array; 66 67 template <typename ValueType, 68 std::size_t NumDims> 69 class multi_array_ref; 70 71 template <typename ValueType, 72 std::size_t NumDims> 73 class const_multi_array_ref; 74 75 multi_array_types::extent_gen extents; 76 multi_array_types::index_gen indices; 77 78 template <typename Array, int N> class subarray_gen; 79 template <typename Array, int N> class const_subarray_gen; 80 template <typename Array, int N> class array_view_gen; 81 template <typename Array, int N> class const_array_view_gen; 82 83 class c_storage_order; 84 class fortran_storage_order; 85 template <std::size_t NumDims> class general_storage_order; 86 87}]]> 88</programlisting> 89</sect1> 90 91&concepts; 92 93<sect1 id="array_types"> 94<title>Array Components</title> 95<para> 96Boost.MultiArray defines an array class, 97<literal>multi_array</literal>, and two adapter classes, 98<literal>multi_array_ref</literal> and 99<literal>const_multi_array_ref</literal>. The three classes model 100MultiArray and so they share a lot of functionality. 101<literal>multi_array_ref</literal> differs from 102<literal>multi_array</literal> in that the 103<literal>multi_array</literal> manages its own memory, while 104<literal>multi_array_ref</literal> is passed a block of memory that it 105expects to be externally managed. 106<literal>const_multi_array_ref</literal> differs from 107<literal>multi_array_ref</literal> in that the underlying elements it 108adapts cannot be modified through its interface, though some array 109properties, including the array shape and index bases, can be altered. 110Functionality the classes have in common is described 111below. 112</para> 113 114<formalpara> 115<title>Note: Preconditions, Effects, and Implementation</title> 116<para> 117Throughout the following sections, small pieces of C++ code are 118used to specify constraints such as preconditions, effects, and 119postconditions. These do not necessarily describe the underlying 120implementation of array components; rather, they describe the 121expected input to and 122behavior of the specified operations. Failure to meet 123preconditions results in undefined behavior. Not all effects 124(i.e. copy constructors, etc.) must be mimicked exactly. The code 125snippets for effects intend to capture the essence of the described 126operation. 127</para> 128</formalpara> 129 130<formalpara> 131<title>Queries</title> 132 133<variablelist> 134<varlistentry> 135<term><programlisting>element* data(); 136const element* data() const;</programlisting></term> 137<listitem> 138<para>This returns a pointer to the beginning of the 139contiguous block that contains the array's data. If all dimensions of 140the array are 0-indexed and stored in ascending order, this is 141equivalent to <literal>origin()</literal>. Note that 142<literal>const_multi_array_ref</literal> only provides the const 143version of this function. 144</para> 145</listitem> 146</varlistentry> 147 148<varlistentry> 149<term><programlisting>element* origin(); 150const element* origin() const;</programlisting></term> 151<listitem> 152<para>This returns the origin element of the 153<literal>multi_array</literal>. Note that 154<literal>const_multi_array_ref</literal> only provides the const 155version of this function. (Required by MultiArray) 156</para> 157</listitem> 158</varlistentry> 159 160<varlistentry> 161<term><function>const index* index_bases();</function></term> 162<listitem> 163<para>This returns the index bases for the 164<literal>multi_array</literal>. (Required by MultiArray) 165</para> 166</listitem> 167</varlistentry> 168 169<varlistentry> 170<term><function>const index* strides();</function></term> 171<listitem> 172<para>This returns the strides for the 173<literal>multi_array</literal>. (Required by MultiArray) 174</para> 175</listitem> 176</varlistentry> 177 178<varlistentry> 179<term><function>const size_type* shape();</function></term> 180<listitem> 181<para>This returns the shape of the 182<literal>multi_array</literal>. (Required by MultiArray) 183</para> 184</listitem> 185</varlistentry> 186</variablelist> 187 188</formalpara> 189 190<formalpara> 191<title>Comparators</title> 192<variablelist> 193<varlistentry> 194<term><programlisting><![CDATA[ 195bool operator==(const *array-type*& rhs); 196bool operator!=(const *array-type*& rhs); 197bool operator<(const *array-type*& rhs); 198bool operator>(const *array-type*& rhs); 199bool operator>=(const *array-type*& rhs); 200bool operator<=(const *array-type*& rhs);]]></programlisting></term> 201 202<listitem> 203<para>Each comparator executes a lexicographical compare over 204the value types of the two arrays. 205(Required by MultiArray) 206</para> 207<formalpara> 208<title>Preconditions</title> 209<para><literal>element</literal> must support the 210comparator corresponding to that called on 211<literal>multi_array</literal>.</para> 212</formalpara> 213 214<formalpara> 215<title>Complexity</title> 216<para>O(<literal>num_elements()</literal>).</para> 217</formalpara> 218 219</listitem> 220</varlistentry> 221 222</variablelist> 223</formalpara> 224 225<formalpara> 226<title>Modifiers</title> 227 228<variablelist> 229 230<varlistentry> 231<term> 232<programlisting> 233<![CDATA[ 234template <typename SizeList> 235void reshape(const SizeList& sizes) 236]]> 237</programlisting> 238</term> 239 240<listitem> 241<para>This changes the shape of the <literal>multi_array</literal>. The 242number of elements and the index bases remain the same, but the number 243of values at each level of the nested container hierarchy may 244change.</para> 245 246<formalpara><title><literal>SizeList</literal> Requirements</title> 247<para><literal>SizeList</literal> must model 248<ulink url="../../utility/Collection.html">Collection</ulink>.</para> 249</formalpara> 250 251<formalpara><title>Preconditions</title> 252<para> 253<programlisting> 254<![CDATA[std::accumulate(sizes.begin(),sizes.end(),size_type(1),std::times<size_type>()) == this->num_elements(); 255sizes.size() == NumDims;]]> 256</programlisting></para> 257</formalpara> 258 259 260<formalpara><title>Postconditions</title> 261<para> 262<literal>std::equal(sizes.begin(),sizes.end(),this->shape) == true;</literal> 263</para> 264</formalpara> 265</listitem> 266</varlistentry> 267 268<varlistentry> 269<term> 270<programlisting> 271<![CDATA[ 272template <typename BaseList> 273void reindex(const BaseList& values); 274]]> 275</programlisting> 276</term> 277<listitem> 278<para>This changes the index bases of the <literal>multi_array</literal> to 279correspond to the the values in <literal>values</literal>.</para> 280 281<formalpara> 282<title><literal>BaseList</literal> Requirements</title> 283<para><literal>BaseList</literal> must model 284<ulink url="../../utility/Collection.html">Collection</ulink>.</para> 285</formalpara> 286 287<formalpara> 288<title>Preconditions</title> 289<para><literal>values.size() == NumDims;</literal></para> 290</formalpara> 291 292 293<formalpara> 294<title>Postconditions</title> 295<para><literal>std::equal(values.begin(),values.end(),this->index_bases()); 296</literal></para> 297</formalpara> 298</listitem> 299</varlistentry> 300 301<varlistentry> 302<term> 303<programlisting> 304<![CDATA[ 305void reindex(index value); 306]]> 307</programlisting> 308</term> 309<listitem> 310<para>This changes the index bases of all dimensions of the 311<literal>multi_array</literal> to <literal>value</literal>.</para> 312 313<formalpara> 314<title>Postconditions</title> 315<para> 316<programlisting> 317<![CDATA[ 318std::count_if(this->index_bases(),this->index_bases()+this->num_dimensions(), 319 std::bind_2nd(std::equal_to<index>(),value)) == 320 this->num_dimensions(); 321]]> 322</programlisting> 323</para> 324</formalpara> 325</listitem> 326</varlistentry> 327 328</variablelist> 329</formalpara> 330 331&multi_array; 332&multi_array_ref; 333&const_multi_array_ref; 334 335</sect1> 336 337 338<sect1 id="auxiliary"> 339 <title>Auxiliary Components</title> 340 341<sect2 id="multi_array_types"> 342<title><literal>multi_array_types</literal></title> 343 344<programlisting> 345<![CDATA[namespace multi_array_types { 346 typedef *unspecified* index; 347 typedef *unspecified* size_type; 348 typedef *unspecified* difference_type; 349 typedef *unspecified* index_range; 350 typedef *unspecified* extent_range; 351 typedef *unspecified* index_gen; 352 typedef *unspecified* extent_gen; 353}]]> 354</programlisting> 355 356<para>Namespace <literal>multi_array_types</literal> defines types 357associated with <literal>multi_array</literal>, 358<literal>multi_array_ref</literal>, and 359<literal>const_multi_array_ref</literal> that are not 360dependent upon template parameters. These types find common use with 361all Boost.Multiarray components. They are defined 362in a namespace from which they can be accessed conveniently. 363With the exception of <literal>extent_gen</literal> and 364<literal>extent_range</literal>, these types fulfill the roles of the 365same name required by MultiArray and are described in its 366concept definition. <literal>extent_gen</literal> and 367<literal>extent_range</literal> are described below. 368</para> 369</sect2> 370 371 372<sect2 id="extent_range"> 373 <title><classname>extent_range</classname></title> 374 375<para><classname>extent_range</classname> objects define half open 376intervals. They provide shape and index base information to 377<literal>multi_array</literal>, <literal>multi_array_ref</literal>, 378 and <literal>const_multi_array_ref</literal> constructors. 379<classname>extent_range</classname>s are passed in 380aggregate to an array constructor (see 381<classname>extent_gen</classname> for more details). 382</para> 383 384<formalpara> 385 <title>Synopsis</title> 386<programlisting><![CDATA[ 387class extent_range { 388public: 389 typedef multi_array_types::index index; 390 typedef multi_array_types::size_type size_type; 391 392 // Structors 393 extent_range(index start, index finish); 394 extent_range(index finish); 395 ~extent_range(); 396 397 // Queries 398 index start(); 399 index finish(); 400 size_type size(); 401};]]></programlisting> 402</formalpara> 403 404 <formalpara> 405 <title>Model Of</title> 406 <para>DefaultConstructible,CopyConstructible</para> 407 </formalpara> 408 409<formalpara><title>Methods and Types</title> 410<variablelist> 411<varlistentry> 412<term><function>extent_range(index start, index finish)</function></term> 413<listitem> 414<para> This constructor defines the half open interval 415<literal>[start,finish)</literal>. The expression 416<literal>finish</literal> must be greater than <literal>start</literal>. 417</para> 418</listitem> 419</varlistentry> 420 421<varlistentry><term><function>extent_range(index finish)</function></term> 422<listitem> 423<para>This constructor defines the half open interval 424<literal>[0,finish)</literal>. The value of <literal>finish</literal> 425must be positive.</para> 426</listitem> 427</varlistentry> 428 429<varlistentry><term><function>index start()</function></term> 430<listitem> 431<para>This function returns the first index represented by the range</para> 432</listitem> 433</varlistentry> 434 435<varlistentry><term><function>index finish()</function></term> 436<listitem> 437<para>This function returns the upper boundary value of the half-open 438interval. Note that the range does not include this value.</para> 439</listitem> 440</varlistentry> 441 442<varlistentry> 443<term><function>size_type size()</function></term> 444<listitem> 445<para>This function returns the size of the specified range. It is 446equivalent to <literal>finish()-start()</literal>.</para> 447</listitem> 448</varlistentry> 449 450</variablelist> 451</formalpara> 452</sect2> 453 454<sect2 id="extent_gen"> 455 <title><classname>extent_gen</classname></title> 456 <para>The <classname>extent_gen</classname> class defines an 457interface for aggregating array shape and indexing information to be 458passed to a <literal>multi_array</literal>, 459<literal>multi_array_ref</literal>, or <literal>const_multi_array_ref</literal> 460constructor. Its interface mimics 461 the syntax used to declare built-in array types 462in C++. For example, while a 3-dimensional array of 463<classname>int</classname> values in C++ would be 464declared as: 465<programlisting>int A[3][4][5],</programlisting> 466a similar <classname>multi_array</classname> would be declared: 467<programlisting>multi_array<int,3> A(extents[3][4][5]).</programlisting> 468</para> 469 470<formalpara><title>Synopsis</title> 471<programlisting>< const; 481 gen_type<NumRanges+1>::type operator[](index idx) const; 482}; 483 484typedef *implementation_defined*<0> extent_gen; 485]]></programlisting> 486</formalpara> 487 488<formalpara><title>Methods and Types</title> 489<variablelist> 490<varlistentry> 491<term><function>template gen_type<Ranges>::type</function></term> 492<listitem> 493<para>This type generator is used to specify the result of 494<literal>Ranges</literal> chained calls to 495<literal>extent_gen::operator[].</literal> The types 496<classname>extent_gen</classname> and 497<classname>gen_type<0>::type</classname> are the same.</para> 498</listitem> 499</varlistentry> 500 501<varlistentry> 502<term><function>gen_type<NumRanges+1>::type 503operator[](const extent_range& a_range) const;</function></term> 504<listitem> 505<para>This function returns a new object containing all previous 506<classname>extent_range</classname> objects in addition to 507<literal>a_range.</literal> <classname>extent_range</classname> 508objects are aggregated by chained calls to 509<function>operator[]</function>.</para> 510</listitem> 511</varlistentry> 512 513<varlistentry> 514<term><function>gen_type<NumRanges+1>::type 515operator[](index idx) const;</function></term> 516<listitem> 517<para>This function returns a new object containing all previous 518<classname>extent_range</classname> objects in addition to 519<literal>extent_range(0,idx).</literal> This function gives the array 520constructors a similar syntax to traditional C multidimensional array 521declaration.</para> 522</listitem> 523</varlistentry> 524 525</variablelist> 526</formalpara> 527</sect2> 528 529<sect2> 530 <title>Global Objects</title> 531 <para>For syntactic convenience, Boost.MultiArray defines two 532global objects as part of its 533interface. These objects play the role of object generators; 534expressions involving them create other objects of interest. 535</para> 536 537 <para> Under some circumstances, the two global objects may be 538considered excessive overhead. Their construction can be prevented by 539defining the preprocessor symbol 540<literal>BOOST_MULTI_ARRAY_NO_GENERATORS</literal> before including 541<filename>boost/multi_array.hpp.</filename></para> 542 543<sect3 id="extents"> 544<title><literal>extents</literal></title> 545 546<programlisting> 547<![CDATA[namespace boost { 548 multi_array_base::extent_gen extents; 549}]]> 550</programlisting> 551 552 <para>Boost.MultiArray's array classes use the 553<literal>extents</literal> global object to specify 554array shape during their construction. 555For example, 556a 3 by 3 by 3 <classname>multi_array</classname> is constructed as follows: 557<programlisting>multi_array<int,3> A(extents[3][3][3]);</programlisting> 558The same array could also be created by explicitly declaring an <literal>extent_gen</literal> 559object locally,, but the global object makes this declaration unnecessary. 560</para> 561</sect3> 562 563<sect3 id="indices"> 564<title><literal>indices</literal></title> 565 566<programlisting> 567<![CDATA[namespace boost { 568 multi_array_base::index_gen indices; 569}]]> 570</programlisting> 571 572 <para>The MultiArray concept specifies an 573<literal>index_gen</literal> associated type that is used to 574create views. 575<literal>indices</literal> is a global object that serves the role of 576<literal>index_gen</literal> for all array components provided by this 577library and their associated subarrays and views. 578</para> 579<para>For example, using the <literal>indices</literal> object, 580a view of an array <literal>A</literal> is constructed as follows: 581<programlisting> 582A[indices[index_range(0,5)][2][index_range(2,4)]]; 583</programlisting> 584</para> 585</sect3> 586</sect2> 587 588<sect2 id="generators"> 589<title>View and SubArray Generators</title> 590<para> 591Boost.MultiArray provides traits classes, <literal>subarray_gen</literal>, 592<literal>const_subarray_gen</literal>, 593<literal>array_view_gen</literal>, 594and <literal>const_array_view_gen</literal>, for naming of 595array associated types within function templates. 596In general this is no more convenient to use than the nested 597type generators, but the library author found that some C++ compilers do not 598properly handle templates nested within function template parameter types. 599These generators constitute a workaround for this deficit. 600The following code snippet illustrates 601the correspondence between the <literal>array_view_gen</literal> 602traits class and the <literal>array_view</literal> type associated to 603an array: 604 605<programlisting> 606template <typename Array> 607void my_function() { 608 typedef typename Array::template array_view<3>::type view1_t; 609 typedef typename boost::array_view_gen<Array,3>::type view2_t; 610 // ... 611} 612</programlisting> 613 614In the above example, <literal>view1_t</literal> and 615<literal>view2_t</literal> have the same type. 616</para> 617</sect2> 618 619 620<sect2 id="memory_layout"> 621<title>Memory Layout Specifiers</title> 622<para> 623While a multidimensional array represents a hierarchy of containers of 624elements, at some point the elements must be laid out in 625memory. As a result, a single multidimensional array 626can be represented in memory more than one way. 627</para> 628 629<para>For example, consider the two dimensional array shown below in 630matrix notation: 631 632<graphic fileref="matrix.gif"/> 633 634Here is how the above array is expressed in C++: 635<programlisting> 636int a[3][4] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; 637</programlisting> 638This is an example of row-major storage, where elements of each row 639are stored contiguously. 640 641While C++ transparently handles accessing elements of an array, you 642can also manage the array and its indexing manually. One way that 643this may be expressed in memory is as follows: 644<programlisting> 645int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; 646int s[] = { 4, 1 }; 647</programlisting> 648 649With the latter declaration of <literal>a</literal> and 650strides <literal>s</literal>, element <literal>a(i,j)</literal> 651of the array can be 652accessed using the expression 653<programlisting>*a+i*s[0]+j*s[1]</programlisting>. 654</para> 655 656<para>The same two dimensional array could be laid out by column as follows: 657 658<programlisting> 659int a[] = { 0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11 }; 660int s[] = { 3, 1 }; 661</programlisting> 662Notice that the strides here are different. As a result, 663The expression given above to access values will work with this pair 664of data and strides as well. 665</para> 666 667<para>In addition to dimension order, it is also possible to 668store any dimension in descending order. For example, returning to the 669first example, the first dimension of the example array, the 670rows, could be stored in 671reverse, resulting in the following: 672 673<programlisting> 674int data[] = { 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3 }; 675int *a = data + 8; 676int s[] = { -4, 1 }; 677</programlisting> 678 679Note that in this example <literal>a</literal> must be explicitly set 680to the origin. In the previous examples, the 681first element stored in memory was the origin; here this is no longer 682the case. 683</para> 684 685<para> 686Alternatively, the second dimension, or the columns, could be reversed 687and the rows stored in ascending order: 688 689<programlisting> 690int data[] = { 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8 }; 691int *a = data + 3; 692int s[] = { 4, -1 }; 693</programlisting> 694</para> 695 696<para> 697Finally, both dimensions could be stored in descending order: 698 699<programlisting> 700int data[] = {11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; 701int *a = data + 11; 702int s[] = { -4, -1 }; 703</programlisting> 704<literal> 705</literal> 706</para> 707 708<para> 709All of the above arrays are equivalent. The expression 710given above for <literal>a(i,j)</literal> will yield the same value 711regardless of the memory layout. 712 713Boost.MultiArray arrays can be created with customized storage 714parameters as described above. Thus, existing data can be adapted 715(with <literal>multi_array_ref</literal> or 716<literal>const_multi_array_ref</literal>) as suited to the array 717abstraction. A common usage of this feature would be to wrap arrays 718that must interoperate with Fortran routines so they can be 719manipulated naturally at both the C++ and Fortran levels. The 720following sections describe the Boost.MultiArray components used to 721specify memory layout. 722</para> 723 724<sect3 id="c_storage_order"> 725<title><literal>c_storage_order</literal></title> 726<programlisting> 727<![CDATA[class c_storage_order { 728 c_storage_order(); 729};]]> 730</programlisting> 731 732<para><literal>c_storage_order</literal> is used to specify that an 733array should store its elements using the same layout as that used by 734primitive C++ multidimensional arrays, that is, from last dimension 735to first. This is the default storage order for the arrays provided by 736this library.</para> 737</sect3> 738 739<sect3 id="fortran_storage_order"> 740<title><literal>fortran_storage_order</literal></title> 741<programlisting> 742<![CDATA[class fortran_storage_order { 743 fortran_storage_order(); 744};]]> 745</programlisting> 746 747<para><literal>fortran_storage_order</literal> is used to specify that 748an array should store its elements using the same memory layout as a 749Fortran multidimensional array would, that is, from first dimension to 750last.</para> 751</sect3> 752 753<sect3 id="general_storage_order"> 754<title><literal>general_storage_order</literal></title> 755<programlisting> 756<![CDATA[template <std::size_t NumDims> 757class general_storage_order { 758 759 template <typename OrderingIter, typename AscendingIter> 760 general_storage_order(OrderingIter ordering, AscendingIter ascending); 761};]]> 762</programlisting> 763 764<para><literal>general_storage_order</literal> allows the user to 765specify an arbitrary memory layout for the contents of an array. The 766constructed object is passed to the array constructor in order to 767specify storage order.</para> 768 769<para> 770<literal>OrderingIter</literal> and <literal>AscendingIter</literal> 771must model the <literal>InputIterator</literal> concept. Both 772iterators must refer to a range of <literal>NumDims</literal> 773elements. <literal>AscendingIter</literal> points to objects 774convertible to <literal>bool</literal>. A value of 775<literal>true</literal> means that a dimension is stored in ascending 776order while <literal>false</literal> means that a dimension is stored 777in descending order. <literal>OrderingIter</literal> specifies the 778order in which dimensions are stored. 779</para> 780 781</sect3> 782</sect2> 783 784<sect2 id="range_checking"> 785<title>Range Checking</title> 786<para> 787By default, the array access methods <literal>operator()</literal> and 788<literal>operator[]</literal> perform range 789checking. If a supplied index is out of the range defined for an 790array, an assertion will abort the program. To disable range 791checking (for performance reasons in production releases), define 792the <literal>BOOST_DISABLE_ASSERTS</literal> preprocessor macro prior to 793including multi_array.hpp in an application. 794</para> 795 796</sect2> 797</sect1> 798 799 800</article> 801