Add a Grid concept
Summary
With C++20 concepts, we have the opportunity to modernize code and get rid of hard-to-reason CRTP patterns. Concepts express type requirements in a much more concise way and give enough information to the compiler to express errors when an interface is not meet. Although compilers are still working on better error messages for concepts, the situation is already much better than for SFINAE and CRTP pattern counterparts. Additionally, concepts may be refined to express additional requirements on the type.
So, this MR attempts to close that gap by introducing concepts for the most important parts of the grid.
Note: This MR was initially implemented using SFINAE concepts by @carsten.graeser and later changed to be C++20 concepts.
Concept Check
You can use the concept to check that grids (or other individual components) fulfill the interface:
// assert that G is a grid
static_assert(Dune::Concept::Grid<Grid>, "G does not implement a dune-grid");
Dune is currently in C++17. That means that concepts should not be used in a way that highers the usage requirements. That's why I have introduced DUNE_GRID_HAVE_CONCEPTS
in the concepts.hh
header. That allow early users to adopt the code and ourselves to check that grids fulfill the interface without necessarily requiring all users to have C++20 (checks are already working in the CI tests of this MR!)
Concept Refinement
Downstream projects that do not need to enforce C++17 may already choose to use extend the concepts in other ways meaningful to them:
// extend grid concept to be a multi-domain grid
template<class G>
concept MultiDomainGrid = Dune::Concept::Grid<G> && requires(G grid, std::size_t domain) {
{ grid.subDomain(domain) } -> Dune::Concept::Grid; // sub-domains shall also be a grid
};
Implementation Details
Dimension loops
To implement the concepts in the grid, we need to loop the dimensions of the grid in a generic form. This is not trivial to achieve in a way that is both "testable" and "debuggable". Thus, what is implemented here is testable and has a fair level of debuggability according to @santiago.ospina and @simon.praetorius experiments. See discussion of alternatives here staging/dune-functions!378 (comment 118730).
Archetypes
Archetypes are types that fulfill the concept requirements of a type and may be used to instantiate generic functions inside of concept definitions (see for example Grid::communicate()
where the data handle argument is a template). These archetypes are just declarations and only introduced to write proper concept checks.
TODO
-
Merge !640 (merged) or separate from this MR -
Squash commits