Flexible compile-time customization
An example - std::vector
// Declaration of the class template, usable with any
// `T` that fulfills the requirements that `vector` poses on it.
template<typename T, typename A = std::allocator<T>>
class vector;
// Instantiation of a concrete vector - a vector of ints.
// The compiler will define this concrete type for us,
// using the definition of the class template.
std::vector<int> v;
Template implementations can be specialized for concrete types
Using class templates, we can write generic algorithms
For some classes, providing all template parameters can be very cumbersome and error-prone.
// Example from dune-pdelab. 9 template parameters!
using GOF0 = Dune::GridOperator<
GFS, GFS, LOP, MBE,
RF, RF, RF,
CF, CF
>;
File:
dune-pdelab/doc/Recipes/recipe-operator-splitting.cc
A usual way to group template parameters
template<class PV, class FSY, class FST, class SSY,...>
struct TwoPVolumeVariablesTraits
{
using PrimaryVariables = PV;
using FluidSystem = FSY;
using FluidState = FST;
using SolidSystem = SSY;
using SolidState = SST;
using PermeabilityType = PT;
using ModelTraits = MT;
using SaturationReconstruction = SR;
};
File:
dumux/dumux/porousmediumflow/2p/model.hh
Why do we need the type?
// Type trait template declaration
template<typename T> struct ValueType;
// Specialization for vectors of T
template<typename T, typename Allocator>
struct ValueType<std::vector<T, Allocator>> { using type = T; };
// Specialization for Dune::FieldVector
template<typename T, int size>
struct ValueType<Dune::FieldVector<T, size>> { using type = T; };
template <class Traits>
class TwoPVolumeVariables
{
...
using FluidSystem = typename Traits::FluidSystem
...
File:
dumux/dumux/porousmediumflow/2p/volumevariables.hh
Usage: these VolumeVariables will work for various FluidSystems:
Inheritance may lead to unexpected results
A simplified example to illustrate the idea
// myproperties.hh
namespace Dumux::Properties {
namespace TTag { struct MyTypeTag {}; }
// some property tag
template<typename TypeTag> struct PropTagA;
// property definition for MyTypeTag
template<>
struct PropTagA<MyTypeTag>
{ using type = /*the actual property*/; };
} // namespace Dumux::Properties
A simplified example to illustrate the idea
template<class TypeTag>
class GenericClass // e.g. LocalResidual
{
using PropA = typename Properties::PropTagA<TypeTag>::type;
using PropB = typename Properties::PropTagB<TypeTag>::type;
// ...
// A property could be, for instance, a fluid system
using FS = typename Properties::FluidSystem<TypeTag>::type;
};
Issue: Inheritance not (easily) possible. All type
traits need to be specialized for MyTypeTag
.
Goal: We would like type tags to be composable via inheritance, while providing a mechanism for customizing any property defined in the hierarchy.
Let’s implement the Vector
example using the property
system
namespace Properties {
namespace TTag { struct BaseTag {}; }
// specialization of the Scalar property for BaseTag
template<class TypeTag>
struct Scalar<TypeTag, TTag::BaseTag> { using type = int; };
// specialization of the Vector property for BaseTag
template<class TypeTag>
struct Vector<TypeTag, TTag::BaseTag> {
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using type = std::vector<Scalar>;
};
Let’s implement the Vector
example using the property
system
Creating new TypeTag nodes
namespace Dumux::Properties::TTag {
struct MyTypeTag {};
struct MyOtherTypeTag
{ using InheritsFrom = std::tuple<MyTypeTag>; }
} // end namespace Dumux::Properties::TTag
File:
dumux-course/exercises/exercise-properties/properties.hh
Creating new property tags (empty, unset properties) \(\leftrightarrow\) Property names are unique!
File:
dumux/test/common/propertysystem/test_propertysystem_aliases.cc
Usually not needed in user code because all necessary properties are already defined in dumux/common/properties.hh.
Setting type properties for a specific type tag
MyTypeTag
namespace Properties {
template<class TypeTag>
struct Problem<TypeTag, TTag::MyTypeTag>
{ using type = Dumux::MyProblem<TypeTag>; };
} // end namespace Properties
File:
dumux-course/exercises/exercise-properties/properties.hh
Alternatively, using type alias properties for a
specific type tag MyTypeTag
namespace Properties::TTag {
struct MyTypeTag {
...
template<class TypeTag>
using Problem = Dumux::MyProblem<TypeTag>;
...
};
} // end namespace Properties
File:
dumux/test/geomechanics/hyperelastic/properties.hh
Setting value properties for a specific type tag
MyTypeTag
namespace Properties{
template<class TypeTag>
struct EnableBoxInterfaceSolver<TypeTag, TTag::MyTypeTag>
{ static constexpr bool value = true; }
} // end namespace Properties
File:
dumux/test/porousmediumflow/2p/boxdfm/properties.hh
Setting value for a alias property for a specific
type tag MyTypeTag
Getting the property type set for a TypeTag
namespace Dumux{
template <class TypeTag>
class Problem
{
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
constexpr auto useIFS = getPropValue<
TypeTag, Properties::EnableBoxInterfaceSolver
>();
};
} // end namespace Dumux
File:
dumux/examples/1ptracer/problem_tracer.hh
template<bool enableRegularization = isRegularized()>
Scalar pcgw(const Scalar sw, const Scalar /*dummySn*/) const
{
...
if constexpr (enableRegularization)^
{
...
}
...
}
File:
dumux/dumux/material/fluidmatrixinteractions/3p/parkervangenuchten.hh
C++ type traits
File:
dumux/dumux/multidomain/fvassembler.hh
C++ type traits
Generic algorithm
template<class CouplingManager>
class Assembler {
void assemble() {
if (SupportsMultithreadedAssembly<CouplingManager>::value)
// assembly multi-threaded
else
// assembly single-threaded
}
};
File:
dumux/dumux/multidomain/fvassembler.hh