Hi everyone, here's my review of Boost.Multi: = What is your evaluation of the design? *Strong, with minor concerns.* Boost.Multi's core design insight — treating a D-dimensional array as a container of (D-1)-dimensional sub-arrays, recursively — is elegant and is what enables full standard library algorithm compatibility. This is the library's primary differentiator and it works well. The type hierarchy is well-motivated. The slicing API is expressive (A(_, 1) for columns, A({0,2}, {0,2}) for sub-blocks, A.strided(2), A.transposed()). The technical rationale includes Godbolt proofs that A[i][j][k] generates identical machine code to manual pointer arithmetic at -O2. *Concerns:* - ~A operator for transposition: A bit surprising — most C++ developers expect bitwise NOT; .transposed() is also available and should be preferred. - nelems() alongside num_elements() is redundant. = What is your evaluation of the implementation? *Solid engineering with areas that need cleanup.* The layout system (detail/layout.hpp) is stride-based and recursive. Extensions use a custom detail::tuple rather than std::tuple, presumably for GPU compatibility. Memory management is correctly implemented. The force_element_trivial<T> trait for opt-in trivial treatment of std::complex types is a practical and well-motivated choice for GPU/performance. Allocator and fancy pointer support is thorough throughout, which is genuinely rare in multidimensional array libraries. *Concerns:* - Lint suppression density: The source code has about 3000 NOLINT annotations (about 200 in array_ref.hpp). Many are justified, but this volume suggests a better approach is needed. - Iterator template complexity: array_iterator carries six template parameters, making compiler error messages potentially very difficult to read. There are no static_assert or concept checks to produce friendly diagnostics. - UB in strided/transposed end() iterators: The documentation acknowledges that end() iterators for strided or transposed views may point to invalid memory (undefined behavior). For a Boost library, this must be resolved or have a fully documented, safe workaround. - dynamic_array move constructor is noexcept(false): This is deliberate but should be prominently documented. - extensions_t<D> has manually unrolled constructors for D=1 through D=6 (~100 lines of near-duplicate code in layout.hpp), which is a maintenance burden. = What is your evaluation of the documentation? *Good tutorial; the reference sections need work.* *Strengths*: - The tutorial is genuinely well-written, building from the problem (manual index computation) up to sorting rows and columns with standard library algorithms. - Godbolt links throughout allow instant verification of claims. - The technical rationale section addresses key design questions honestly (why A[i][j][k], why static dimensionality, why C++17). - Comparison tables vs. mdspan, mdarray, xtensor, Boost.MultiArray are clear and fair. - The reference page has a useful cheat-sheet table. *Weaknesses:* - No automated API reference extraction: The reference is manually written, which could make it drift from the implementation. - Thread safety is undocumented: In particular, dynamic_array is described as useful for multithreaded contexts, but no formal guarantees are stated. - No migration/interop guide from Boost.MultiArray or std::mdspan. = What is your evaluation of the potential usefulness of the library? *High.* The library fills a genuine gap in the C++ ecosystem. No other library that I know of provides this combination of: - Full standard library algorithm compatibility: You can std::sort() rows, std::transform() columns, std::copy() sub-blocks. This is impossible or extremely awkward with std::mdspan, Eigen, or Boost.MultiArray. - An owning n-dimensional container: std::mdspan is non-owning only; std::mdarray is not yet standardized. - GPU memory support (CUDA + HIP). - Fancy pointer support (e.g. boost::interprocess::offset_ptr for persistent/shared memory). Target users include scientific computing, image processing, numerical simulation, and ML/AI. The examples include a heat equation solver, LU factorization, Gauss-Jordan solve, Boost.Interprocess mapped files, MPI usage, and Boost.GIL integration — all realistic use cases. I haven't used it in production, but its feature set directly addresses pain points I've run into in scientific C++ projects. = Did you try to use the library? With which compiler(s)? Did you have any problems? *I didn't compile the library, but I reviewed the source code, test suite, examples, benchmarks and CI configuration.* = How much effort did you put into your evaluation? A glance? A quick reading? In-depth study? *In-depth study.* I cloned the repository and read the core headers, the full documentation source, the online rendered docs, the CMakeLists.txt, the test files, the examples, and benchmarks. I examined class hierarchy, iterator design, const-correctness, allocator support, and portability workarounds. = Are you knowledgeable about the problem domain? *Moderately knowledgeable.* I'm familiar with the math concepts and have some experience with scientific computing and numerical methods. = Verdict: CONDITIONAL ACCEPT Rationale for acceptance: - Fills a genuine, well-articulated gap (see above). - The API is well-designed with clear value/reference semantic distinctions. - Broad compiler support. - Good documentation with a strong tutorial and honest technical rationale. Conditions for acceptance: - Resolve the UB in strided/transposed end() iterators. - Document thread safety guarantees. - Reduce Lint suppression density. Suggestions (not conditions): - Add a migration/interop guide for Boost.MultiArray and std::mdspan users. - Consider removing operator~() in favor of transposed() only. - Decide between nelems() and num_elements(). - Add automated API reference generation (MrDocs?). - Reduce extensions_t constructor unrolling with variadic templates where compiler support allows. -- Gennaro Prota <https://prota.dev>