File traits.hxx

namespace bout

SNB model

namespace utils

Typedefs

using is_Field = std::is_base_of<Field, T>

If T is derived from Field, provides the member constant value equal to true. Otherwise value isfalse`.

The following is C++14, but simplifies the use of is_field:

template <class T>
constexpr bool is_field_v = is_field<T>::value;

Examples

template <class T>
void print_field(const T& field) {
  static_assert(bout::utils::is_field<T>::value,
      "print_field only works with Field2Ds, Field3Ds or FieldPerps")
  // implementation
}

using is_Field2D = std::is_base_of<Field2D, T>

If T is derived from Field2D, provides the member constant value equal to true. Otherwise value isfalse`.

using is_Field3D = std::is_base_of<Field3D, T>

If T is derived from Field3D, provides the member constant value equal to true. Otherwise value isfalse`.

using is_FieldPerp = std::is_base_of<FieldPerp, T>

If T is derived from FieldPerp, provides the member constant value equal to true. Otherwise value isfalse`.

using EnableIfField = typename std::enable_if<details::and_all(is_Field<Ts>::value...), typename std::common_type<Ts...>::type>::type

Enable a function if all the Ts are subclasses of Field, and returns the common type: i.e. Field3D if at least one argument is Field3D, otherwise Field2D if they are all Field2D

This is most useful in two particular cases:

  1. when there are multiple overloads for a function but some only make sense for fields (as opposed to BoutReal, say) or vice-versa, and some overloads should not be used for fields
  2. when a function takes multiple fields and the return type is also a field and must be “big enough”

In other cases, such as a function without overloads that only works for fields, consider using static_assert with is_Field to give a nice compile-time error

Examples

Consider the following template function:

template <class T, class U, class V,
     class ResultType = typename bout::utils::EnableIfField<T, U, V>>
auto where(const T& test, const U& gt0, const V& le0) -> ResultType {
  // function body
}

This function only “appears” if T, U and V are all subclasses of Field. ResultType is the common type of T, U and V. If T and U are both Field2D, ResultType is Field2D if V is Field2D, and Field3D if V is Field3D.

using EnableIfField2D = typename std::enable_if<details::and_all(is_Field2D<Ts>::value...), typename std::common_type<Ts...>::type>::type

Enable a function if all the Ts are subclasses of Field2D, and returns the common type

using EnableIfField3D = typename std::enable_if<details::and_all(is_Field3D<Ts>::value...), typename std::common_type<Ts...>::type>::type

Enable a function if all the Ts are subclasses of Field3D, and returns the common type

using EnableIfFieldPerp = typename std::enable_if<details::and_all(is_FieldPerp<Ts>::value...), typename std::common_type<Ts...>::type>::type

Enable a function if all the Ts are subclasses of FieldPerp, and returns the common type

namespace details

Functions

constexpr bool and_all()

Helper class for fold expressions pre-C++17

Taken from “C++ Templates: The Complete Guide, Second Edition” Addison-Wesley, 2017 ISBN-13: 978-0-321-71412-1 ISBN-10: 0-321-71412-1 Copyright © 2017 by Addison-Wesley, David Vandevoorde, Nicolai M. Josuttis, and Douglas Gregor.

template<class T>
constexpr bool and_all(T cond)
template<class T, class ...Ts>
constexpr bool and_all(T cond, Ts... conds)