Also provide a bunch of doc strings for the involved functions. Then also replace
all of the current uses of the is_detected type by constexpr variables.
DEAL_II_NAMESPACE_OPEN
-// Detection idiom from Version 2 of the C++ Extensions for Library
+// Detection idiom adapted from Version 2 of the C++ Extensions for Library
// Fundamentals, ISO/IEC TS 19568:2017
namespace internal
{
+ /**
+ * A namespace used to declare the machinery for detecting whether a specific
+ * class supports an operation. This approach simulates C++20-style
+ * concepts with language standards before C++20.
+ */
namespace SupportsOperation
{
template <class...>
using void_t = void;
- // primary template handles all types not supporting the archetypal Op
+ /**
+ * The primary template class used in detecting operations. If the
+ * compiler does not choose the specialization, then the fall-back
+ * case is this general template, which then declares member variables
+ * and types according to the failed detection.
+ */
template <class Default,
- class /*AlwaysVoid*/,
+ class AlwaysVoid,
template <class...>
class Op,
- class... /*Args*/>
+ class... Args>
struct detector
{
using value_t = std::false_type;
using type = Default;
};
- // specialization recognizes and handles only types supporting Op
+ /**
+ * A specialization of the general template.
+ *
+ * The trick this class uses is that, just like the general template,
+ * its second argument is always `void`, but here it is written as
+ * `void_t<Op<Args...>>` and consequently the compiler will only select this
+ * specialization if `Op<Args...>` is in fact a valid type. This means that
+ * the operation we seek to understand is indeed supported.
+ *
+ * This specialization then declares member variables and types according
+ * to the successful detection.
+ */
template <class Default, template <class...> class Op, class... Args>
struct detector<Default, void_t<Op<Args...>>, Op, Args...>
{
};
- // base class for nonesuch to inherit from so it is not an aggregate
+ /**
+ * A base class for the `nonesuch` type to inherit from so it is not an
+ * aggregate.
+ */
struct nonesuch_base
{};
+ /**
+ * A type that can not be used in any reasonable way and consequently
+ * can be used to indicate a failed detection in template metaprogramming.
+ */
struct nonesuch : private nonesuch_base
{
~nonesuch() = delete;
operator=(nonesuch const &) = delete;
};
- } // namespace SupportsOperation
+ template <class Default, template <class...> class Op, class... Args>
+ using detected_or = detector<Default, void, Op, Args...>;
- template <class Default, template <class...> class Op, class... Args>
- using detected_or =
- internal::SupportsOperation::detector<Default, void, Op, Args...>;
+ template <template <class...> class Op, class... Args>
+ using is_detected = typename detected_or<nonesuch, Op, Args...>::value_t;
- template <template <class...> class Op, class... Args>
- using is_detected =
- typename detected_or<SupportsOperation::nonesuch, Op, Args...>::value_t;
+ template <template <class...> class Op, class... Args>
+ using detected_t = typename detected_or<nonesuch, Op, Args...>::type;
- template <template <class...> class Op, class... Args>
- using detected_t =
- typename detected_or<SupportsOperation::nonesuch, Op, Args...>::type;
+ template <class Default, template <class...> class Op, class... Args>
+ using detected_or_t = typename detected_or<Default, Op, Args...>::type;
- template <class Default, template <class...> class Op, class... Args>
- using detected_or_t = typename detected_or<Default, Op, Args...>::type;
+ template <class Expected, template <class...> class Op, class... Args>
+ using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
+
+ template <class To, template <class...> class Op, class... Args>
+ using is_detected_convertible =
+ std::is_convertible<detected_t<Op, Args...>, To>;
+ } // namespace SupportsOperation
- template <class Expected, template <class...> class Op, class... Args>
- using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
- template <class To, template <class...> class Op, class... Args>
- using is_detected_convertible =
- std::is_convertible<detected_t<Op, Args...>, To>;
+ /**
+ * A `constexpr` variable that describes whether or not `Op<Args...>` is a
+ * valid expression.
+ *
+ * The way this is used is to define an `Op` operation template that
+ * describes the operation we want to perform, and `Args` is a template
+ * pack that describes the arguments to the operation. This variable
+ * then states whether the operation, with these arguments, leads to
+ * a valid C++ expression.
+ *
+ * An example is if one wanted to find out whether a type `T` has
+ * a `get_mpi_communicator()` member function. In that case, one would write
+ * the operation as
+ * @code
+ * template <typename T>
+ * using get_mpi_communicator_op
+ * = decltype(std::declval<T>().get_mpi_communicator());
+ * @endcode
+ * and could define a variable like
+ * @code
+ * template <typename T>
+ * constexpr bool has_get_mpi_communicator =
+ * is_supported_operation<get_mpi_communicator_op, T>;
+ * @endcode
+ *
+ * The trick used here is that `get_mpi_communicator_op` is a general
+ * template, but when used with a type that does *not* have a
+ * `get_mpi_communicator()` member variable, the `decltype(...)` operation
+ * will fail because its argument does not represent a valid expression for
+ * such a type. In other words, for such types `T` that do not have such a
+ * member function, the general template `get_mpi_communicator_op` represents
+ * a valid declaration, but the instantiation `get_mpi_communicator_op<T>`
+ * is not, and the variable declared here detects and reports this.
+ */
+ template <template <class...> class Op, class... Args>
+ constexpr bool is_supported_operation =
+ SupportsOperation::is_detected<Op, Args...>::value;
} // namespace internal
decltype(std::begin(std::declval<T>()), std::end(std::declval<T>()));
template <typename T>
-using has_begin_and_end = internal::is_detected<begin_and_end_t, T>;
+using has_begin_and_end =
+ internal::SupportsOperation::is_detected<begin_and_end_t, T>;
decltype(std::declval<T>().get_mpi_communicator());
template <typename T>
- using has_get_mpi_communicator = is_detected<get_mpi_communicator_t, T>;
+ static constexpr bool has_get_mpi_communicator =
+ is_supported_operation<get_mpi_communicator_t, T>;
// A helper type-trait that leverage SFINAE to figure out if type T has
// void T::locally_owned_domain_indices()
decltype(std::declval<T>().locally_owned_domain_indices());
template <typename T>
- using has_locally_owned_domain_indices =
- is_detected<locally_owned_domain_indices_t, T>;
+ static constexpr bool has_locally_owned_domain_indices =
+ is_supported_operation<locally_owned_domain_indices_t, T>;
// A helper type-trait that leverage SFINAE to figure out if type T has
// void T::locally_owned_range_indices()
decltype(std::declval<T>().locally_owned_range_indices());
template <typename T>
- using has_locally_owned_range_indices =
- is_detected<locally_owned_range_indices_t, T>;
+ static constexpr bool has_locally_owned_range_indices =
+ is_supported_operation<locally_owned_range_indices_t, T>;
// A helper type-trait that leverage SFINAE to figure out if type T has
// void T::initialize_dof_vector(VectorType v)
decltype(std::declval<T>().initialize_dof_vector());
template <typename T>
- using has_initialize_dof_vector = is_detected<initialize_dof_vector_t, T>;
+ static constexpr bool has_initialize_dof_vector =
+ is_supported_operation<initialize_dof_vector_t, T>;
// Used for (Trilinos/PETSc)Wrappers::SparseMatrix
- template <typename MatrixType,
- typename std::enable_if<
- has_get_mpi_communicator<MatrixType>::value &&
- has_locally_owned_domain_indices<MatrixType>::value,
- MatrixType>::type * = nullptr>
+ template <
+ typename MatrixType,
+ typename std::enable_if<has_get_mpi_communicator<MatrixType> &&
+ has_locally_owned_domain_indices<MatrixType>,
+ MatrixType>::type * = nullptr>
static void
reinit_domain_vector(MatrixType & mat,
LinearAlgebra::distributed::Vector<Number> &vec,
}
// Used for MatrixFree and DiagonalMatrix
- template <
- typename MatrixType,
- typename std::enable_if<has_initialize_dof_vector<MatrixType>::value,
- MatrixType>::type * = nullptr>
+ template <typename MatrixType,
+ typename std::enable_if<has_initialize_dof_vector<MatrixType>,
+ MatrixType>::type * = nullptr>
static void
reinit_domain_vector(MatrixType & mat,
LinearAlgebra::distributed::Vector<Number> &vec,
}
// Used for (Trilinos/PETSc)Wrappers::SparseMatrix
- template <typename MatrixType,
- typename std::enable_if<
- has_get_mpi_communicator<MatrixType>::value &&
- has_locally_owned_range_indices<MatrixType>::value,
- MatrixType>::type * = nullptr>
+ template <
+ typename MatrixType,
+ typename std::enable_if<has_get_mpi_communicator<MatrixType> &&
+ has_locally_owned_range_indices<MatrixType>,
+ MatrixType>::type * = nullptr>
static void
reinit_range_vector(MatrixType & mat,
LinearAlgebra::distributed::Vector<Number> &vec,
}
// Used for MatrixFree and DiagonalMatrix
- template <
- typename MatrixType,
- typename std::enable_if<has_initialize_dof_vector<MatrixType>::value,
- MatrixType>::type * = nullptr>
+ template <typename MatrixType,
+ typename std::enable_if<has_initialize_dof_vector<MatrixType>,
+ MatrixType>::type * = nullptr>
static void
reinit_range_vector(MatrixType & mat,
LinearAlgebra::distributed::Vector<Number> &vec,
std::declval<const VectorType &>()));
template <typename T, typename VectorType>
- using has_Tvmult = is_detected<Tvmult_t, T, VectorType>;
+ constexpr bool has_Tvmult = is_supported_operation<Tvmult_t, T, VectorType>;
template <typename T, typename VectorType>
using step_t = decltype(
std::declval<const VectorType &>()));
template <typename T, typename VectorType>
- using has_step = is_detected<step_t, T, VectorType>;
+ constexpr bool has_step = is_supported_operation<step_t, T, VectorType>;
template <typename T, typename VectorType>
using step_omega_t =
std::declval<const double>()));
template <typename T, typename VectorType>
- using has_step_omega = is_detected<step_omega_t, T, VectorType>;
+ constexpr bool has_step_omega =
+ is_supported_operation<step_omega_t, T, VectorType>;
template <typename T, typename VectorType>
using Tstep_t = decltype(
std::declval<const VectorType &>()));
template <typename T, typename VectorType>
- using has_Tstep = is_detected<Tstep_t, T, VectorType>;
+ constexpr bool has_Tstep = is_supported_operation<Tstep_t, T, VectorType>;
template <typename T, typename VectorType>
using Tstep_omega_t =
std::declval<const double>()));
template <typename T, typename VectorType>
- using has_Tstep_omega = is_detected<Tstep_omega_t, T, VectorType>;
+ constexpr bool has_Tstep_omega =
+ is_supported_operation<Tstep_omega_t, T, VectorType>;
template <typename T, typename VectorType>
using jacobi_step_t = decltype(
std::declval<const double>()));
template <typename T, typename VectorType>
- using has_jacobi_step = is_detected<jacobi_step_t, T, VectorType>;
+ constexpr bool has_jacobi_step =
+ is_supported_operation<jacobi_step_t, T, VectorType>;
template <typename T, typename VectorType>
using SOR_step_t = decltype(
std::declval<const double>()));
template <typename T, typename VectorType>
- using has_SOR_step = is_detected<SOR_step_t, T, VectorType>;
+ constexpr bool has_SOR_step =
+ is_supported_operation<SOR_step_t, T, VectorType>;
template <typename T, typename VectorType>
using SSOR_step_t = decltype(
std::declval<const double>()));
template <typename T, typename VectorType>
- using has_SSOR_step = is_detected<SSOR_step_t, T, VectorType>;
+ constexpr bool has_SSOR_step =
+ is_supported_operation<SSOR_step_t, T, VectorType>;
template <typename MatrixType>
class PreconditionJacobiImpl
this->vmult(dst, src);
}
- template <
- typename VectorType,
- typename std::enable_if<has_jacobi_step<MatrixType, VectorType>::value,
- MatrixType>::type * = nullptr>
+ template <typename VectorType,
+ typename std::enable_if<has_jacobi_step<MatrixType, VectorType>,
+ MatrixType>::type * = nullptr>
void
step(VectorType &dst, const VectorType &src) const
{
template <
typename VectorType,
- typename std::enable_if<!has_jacobi_step<MatrixType, VectorType>::value,
+ typename std::enable_if<!has_jacobi_step<MatrixType, VectorType>,
MatrixType>::type * = nullptr>
void
step(VectorType &, const VectorType &) const
this->A->precondition_TSOR(dst, src, this->relaxation);
}
- template <
- typename VectorType,
- typename std::enable_if<has_SOR_step<MatrixType, VectorType>::value,
- MatrixType>::type * = nullptr>
+ template <typename VectorType,
+ typename std::enable_if<has_SOR_step<MatrixType, VectorType>,
+ MatrixType>::type * = nullptr>
void
step(VectorType &dst, const VectorType &src) const
{
this->A->SOR_step(dst, src, this->relaxation);
}
- template <
- typename VectorType,
- typename std::enable_if<!has_SOR_step<MatrixType, VectorType>::value,
- MatrixType>::type * = nullptr>
+ template <typename VectorType,
+ typename std::enable_if<!has_SOR_step<MatrixType, VectorType>,
+ MatrixType>::type * = nullptr>
void
step(VectorType &, const VectorType &) const
{
ExcMessage("Matrix A does not provide a SOR_step() function!"));
}
- template <
- typename VectorType,
- typename std::enable_if<has_SOR_step<MatrixType, VectorType>::value,
- MatrixType>::type * = nullptr>
+ template <typename VectorType,
+ typename std::enable_if<has_SOR_step<MatrixType, VectorType>,
+ MatrixType>::type * = nullptr>
void
Tstep(VectorType &dst, const VectorType &src) const
{
this->A->TSOR_step(dst, src, this->relaxation);
}
- template <
- typename VectorType,
- typename std::enable_if<!has_SOR_step<MatrixType, VectorType>::value,
- MatrixType>::type * = nullptr>
+ template <typename VectorType,
+ typename std::enable_if<!has_SOR_step<MatrixType, VectorType>,
+ MatrixType>::type * = nullptr>
void
Tstep(VectorType &, const VectorType &) const
{
pos_right_of_diagonal);
}
- template <
- typename VectorType,
- typename std::enable_if<has_SSOR_step<MatrixType, VectorType>::value,
- MatrixType>::type * = nullptr>
+ template <typename VectorType,
+ typename std::enable_if<has_SSOR_step<MatrixType, VectorType>,
+ MatrixType>::type * = nullptr>
void
step(VectorType &dst, const VectorType &src) const
{
this->A->SSOR_step(dst, src, this->relaxation);
}
- template <
- typename VectorType,
- typename std::enable_if<!has_SSOR_step<MatrixType, VectorType>::value,
- MatrixType>::type * = nullptr>
+ template <typename VectorType,
+ typename std::enable_if<!has_SSOR_step<MatrixType, VectorType>,
+ MatrixType>::type * = nullptr>
void
step(VectorType &, const VectorType &) const
{
const std::vector<size_type> &inverse_permutation;
};
- template <typename MatrixType,
- typename PreconditionerType,
- typename VectorType,
- typename std::enable_if<
- has_step_omega<PreconditionerType, VectorType>::value,
- PreconditionerType>::type * = nullptr>
+ template <
+ typename MatrixType,
+ typename PreconditionerType,
+ typename VectorType,
+ typename std::enable_if<has_step_omega<PreconditionerType, VectorType>,
+ PreconditionerType>::type * = nullptr>
void
step(const MatrixType &,
const PreconditionerType &preconditioner,
preconditioner.step(dst, src, relaxation);
}
- template <typename MatrixType,
- typename PreconditionerType,
- typename VectorType,
- typename std::enable_if<
- !has_step_omega<PreconditionerType, VectorType>::value &&
- has_step<PreconditionerType, VectorType>::value,
- PreconditionerType>::type * = nullptr>
+ template <
+ typename MatrixType,
+ typename PreconditionerType,
+ typename VectorType,
+ typename std::enable_if<!has_step_omega<PreconditionerType, VectorType> &&
+ has_step<PreconditionerType, VectorType>,
+ PreconditionerType>::type * = nullptr>
void
step(const MatrixType &,
const PreconditionerType &preconditioner,
preconditioner.step(dst, src);
}
- template <typename MatrixType,
- typename PreconditionerType,
- typename VectorType,
- typename std::enable_if<
- !has_step_omega<PreconditionerType, VectorType>::value &&
- !has_step<PreconditionerType, VectorType>::value,
- PreconditionerType>::type * = nullptr>
+ template <
+ typename MatrixType,
+ typename PreconditionerType,
+ typename VectorType,
+ typename std::enable_if<!has_step_omega<PreconditionerType, VectorType> &&
+ !has_step<PreconditionerType, VectorType>,
+ PreconditionerType>::type * = nullptr>
void
step(const MatrixType & A,
const PreconditionerType &preconditioner,
dst.add(relaxation, tmp);
}
- template <typename MatrixType,
- typename PreconditionerType,
- typename VectorType,
- typename std::enable_if<
- has_Tstep_omega<PreconditionerType, VectorType>::value,
- PreconditionerType>::type * = nullptr>
+ template <
+ typename MatrixType,
+ typename PreconditionerType,
+ typename VectorType,
+ typename std::enable_if<has_Tstep_omega<PreconditionerType, VectorType>,
+ PreconditionerType>::type * = nullptr>
void
Tstep(const MatrixType &,
const PreconditionerType &preconditioner,
typename PreconditionerType,
typename VectorType,
typename std::enable_if<
- !has_Tstep_omega<PreconditionerType, VectorType>::value &&
- has_Tstep<PreconditionerType, VectorType>::value,
+ !has_Tstep_omega<PreconditionerType, VectorType> &&
+ has_Tstep<PreconditionerType, VectorType>,
PreconditionerType>::type * = nullptr>
void
Tstep(const MatrixType &,
template <typename MatrixType,
typename VectorType,
- typename std::enable_if<has_Tvmult<MatrixType, VectorType>::value,
+ typename std::enable_if<has_Tvmult<MatrixType, VectorType>,
MatrixType>::type * = nullptr>
void
Tvmult(const MatrixType &A, VectorType &dst, const VectorType &src)
A.Tvmult(dst, src);
}
- template <
- typename MatrixType,
- typename VectorType,
- typename std::enable_if<!has_Tvmult<MatrixType, VectorType>::value,
- MatrixType>::type * = nullptr>
+ template <typename MatrixType,
+ typename VectorType,
+ typename std::enable_if<!has_Tvmult<MatrixType, VectorType>,
+ MatrixType>::type * = nullptr>
void
Tvmult(const MatrixType &, VectorType &, const VectorType &)
{
typename PreconditionerType,
typename VectorType,
typename std::enable_if<
- !has_Tstep_omega<PreconditionerType, VectorType>::value &&
- !has_Tstep<PreconditionerType, VectorType>::value,
+ !has_Tstep_omega<PreconditionerType, VectorType> &&
+ !has_Tstep<PreconditionerType, VectorType>,
PreconditionerType>::type * = nullptr>
void
Tstep(const MatrixType & A,
}
template <typename VectorType,
- typename std::enable_if<has_shared_vector_data<VectorType>::value,
+ typename std::enable_if<has_shared_vector_data<VectorType>,
VectorType>::type * = nullptr>
const std::vector<ArrayView<const typename VectorType::value_type>> *
get_shared_vector_data(VectorType & vec,
}
template <typename VectorType,
- typename std::enable_if<!has_shared_vector_data<VectorType>::value,
+ typename std::enable_if<!has_shared_vector_data<VectorType>,
VectorType>::type * = nullptr>
const std::vector<ArrayView<const typename VectorType::value_type>> *
get_shared_vector_data(VectorType &,
typename VectorType,
typename EvaluatorType,
typename std::enable_if<
- internal::has_begin<VectorType>::value &&
+ internal::has_begin<VectorType> &&
std::is_same<decltype(std::declval<VectorType>().begin()),
Number *>::value,
VectorType>::type * = nullptr>
typename VectorType,
typename EvaluatorType,
typename std::enable_if<
- !internal::has_begin<VectorType>::value ||
+ !internal::has_begin<VectorType> ||
!std::is_same<decltype(std::declval<VectorType>().begin()),
Number *>::value,
VectorType>::type * = nullptr>
* Start update_ghost_value for vectors that do not support
* the split into _start() and finish() stages
*/
- template <typename VectorType,
- typename std::enable_if<
- !has_update_ghost_values_start<VectorType>::value &&
- !is_not_parallel_vector<VectorType>::value,
- VectorType>::type * = nullptr>
+ template <
+ typename VectorType,
+ typename std::enable_if<!has_update_ghost_values_start<VectorType> &&
+ !is_not_parallel_vector<VectorType>::value,
+ VectorType>::type * = nullptr>
void
update_ghost_values_start(const unsigned int component_in_block_vector,
const VectorType & vec)
* the split into _start() and finish() stages, but don't support
* exchange on a subset of DoFs
*/
- template <typename VectorType,
- typename std::enable_if<
- has_update_ghost_values_start<VectorType>::value &&
- !has_exchange_on_subset<VectorType>::value,
- VectorType>::type * = nullptr>
+ template <
+ typename VectorType,
+ typename std::enable_if<has_update_ghost_values_start<VectorType> &&
+ !has_exchange_on_subset<VectorType>,
+ VectorType>::type * = nullptr>
void
update_ghost_values_start(const unsigned int component_in_block_vector,
const VectorType & vec)
* exchange on a subset of DoFs,
* i.e. LinearAlgebra::distributed::Vector
*/
- template <typename VectorType,
- typename std::enable_if<
- has_update_ghost_values_start<VectorType>::value &&
- has_exchange_on_subset<VectorType>::value,
- VectorType>::type * = nullptr>
+ template <
+ typename VectorType,
+ typename std::enable_if<has_update_ghost_values_start<VectorType> &&
+ has_exchange_on_subset<VectorType>,
+ VectorType>::type * = nullptr>
void
update_ghost_values_start(const unsigned int component_in_block_vector,
const VectorType & vec)
*/
template <
typename VectorType,
- typename std::enable_if<!has_update_ghost_values_start<VectorType>::value,
+ typename std::enable_if<!has_update_ghost_values_start<VectorType>,
VectorType>::type * = nullptr>
void
update_ghost_values_finish(const unsigned int /*component_in_block_vector*/,
* the split into _start() and finish() stages, but don't support
* exchange on a subset of DoFs
*/
- template <typename VectorType,
- typename std::enable_if<
- has_update_ghost_values_start<VectorType>::value &&
- !has_exchange_on_subset<VectorType>::value,
- VectorType>::type * = nullptr>
+ template <
+ typename VectorType,
+ typename std::enable_if<has_update_ghost_values_start<VectorType> &&
+ !has_exchange_on_subset<VectorType>,
+ VectorType>::type * = nullptr>
void
update_ghost_values_finish(const unsigned int component_in_block_vector,
const VectorType & vec)
* exchange on a subset of DoFs,
* i.e. LinearAlgebra::distributed::Vector
*/
- template <typename VectorType,
- typename std::enable_if<
- has_update_ghost_values_start<VectorType>::value &&
- has_exchange_on_subset<VectorType>::value,
- VectorType>::type * = nullptr>
+ template <
+ typename VectorType,
+ typename std::enable_if<has_update_ghost_values_start<VectorType> &&
+ has_exchange_on_subset<VectorType>,
+ VectorType>::type * = nullptr>
void
update_ghost_values_finish(const unsigned int component_in_block_vector,
const VectorType & vec)
*/
template <
typename VectorType,
- typename std::enable_if<!has_compress_start<VectorType>::value &&
+ typename std::enable_if<!has_compress_start<VectorType> &&
!is_not_parallel_vector<VectorType>::value,
VectorType>::type * = nullptr>
void
* the split into _start() and finish() stages, but don't support
* exchange on a subset of DoFs
*/
- template <
- typename VectorType,
- typename std::enable_if<has_compress_start<VectorType>::value &&
- !has_exchange_on_subset<VectorType>::value,
- VectorType>::type * = nullptr>
+ template <typename VectorType,
+ typename std::enable_if<has_compress_start<VectorType> &&
+ !has_exchange_on_subset<VectorType>,
+ VectorType>::type * = nullptr>
void
compress_start(const unsigned int component_in_block_vector,
VectorType & vec)
* exchange on a subset of DoFs,
* i.e. LinearAlgebra::distributed::Vector
*/
- template <
- typename VectorType,
- typename std::enable_if<has_compress_start<VectorType>::value &&
- has_exchange_on_subset<VectorType>::value,
- VectorType>::type * = nullptr>
+ template <typename VectorType,
+ typename std::enable_if<has_compress_start<VectorType> &&
+ has_exchange_on_subset<VectorType>,
+ VectorType>::type * = nullptr>
void
compress_start(const unsigned int component_in_block_vector,
VectorType & vec)
* the split into _start() and finish() stages and serial vectors
*/
template <typename VectorType,
- typename std::enable_if<!has_compress_start<VectorType>::value,
+ typename std::enable_if<!has_compress_start<VectorType>,
VectorType>::type * = nullptr>
void
compress_finish(const unsigned int /*component_in_block_vector*/,
* the split into _start() and finish() stages, but don't support
* exchange on a subset of DoFs
*/
- template <
- typename VectorType,
- typename std::enable_if<has_compress_start<VectorType>::value &&
- !has_exchange_on_subset<VectorType>::value,
- VectorType>::type * = nullptr>
+ template <typename VectorType,
+ typename std::enable_if<has_compress_start<VectorType> &&
+ !has_exchange_on_subset<VectorType>,
+ VectorType>::type * = nullptr>
void
compress_finish(const unsigned int component_in_block_vector,
VectorType & vec)
* exchange on a subset of DoFs,
* i.e. LinearAlgebra::distributed::Vector
*/
- template <
- typename VectorType,
- typename std::enable_if<has_compress_start<VectorType>::value &&
- has_exchange_on_subset<VectorType>::value,
- VectorType>::type * = nullptr>
+ template <typename VectorType,
+ typename std::enable_if<has_compress_start<VectorType> &&
+ has_exchange_on_subset<VectorType>,
+ VectorType>::type * = nullptr>
void
compress_finish(const unsigned int component_in_block_vector,
VectorType & vec)
*/
template <
typename VectorType,
- typename std::enable_if<!has_exchange_on_subset<VectorType>::value &&
+ typename std::enable_if<!has_exchange_on_subset<VectorType> &&
!is_not_parallel_vector<VectorType>::value,
VectorType>::type * = nullptr>
void
* LinearAlgebra::distributed::Vector
*/
template <typename VectorType,
- typename std::enable_if<has_exchange_on_subset<VectorType>::value,
+ typename std::enable_if<has_exchange_on_subset<VectorType>,
VectorType>::type * = nullptr>
void
reset_ghost_values(const VectorType &vec) const
* i.e. LinearAlgebra::distributed::Vector
*/
template <typename VectorType,
- typename std::enable_if<has_exchange_on_subset<VectorType>::value,
+ typename std::enable_if<has_exchange_on_subset<VectorType>,
VectorType>::type * = nullptr>
void
zero_vector_region(const unsigned int range_index, VectorType &vec) const
* subset of DoFs <==> begin() + ind == local_element(ind) but are still a
* vector type
*/
- template <
- typename VectorType,
- typename std::enable_if<!has_exchange_on_subset<VectorType>::value,
- VectorType>::type * = nullptr,
- typename VectorType::value_type * = nullptr>
+ template <typename VectorType,
+ typename std::enable_if<!has_exchange_on_subset<VectorType>,
+ VectorType>::type * = nullptr,
+ typename VectorType::value_type * = nullptr>
void
zero_vector_region(const unsigned int range_index, VectorType &vec) const
{
// would be too many outstanding communication requests.
// default value for vectors that do not have communication_block_size
- template <
- typename VectorStruct,
- typename std::enable_if<!has_communication_block_size<VectorStruct>::value,
- VectorStruct>::type * = nullptr>
+ template <typename VectorStruct,
+ typename std::enable_if<!has_communication_block_size<VectorStruct>,
+ VectorStruct>::type * = nullptr>
constexpr unsigned int
get_communication_block_size(const VectorStruct &)
{
- template <
- typename VectorStruct,
- typename std::enable_if<has_communication_block_size<VectorStruct>::value,
- VectorStruct>::type * = nullptr>
+ template <typename VectorStruct,
+ typename std::enable_if<has_communication_block_size<VectorStruct>,
+ VectorStruct>::type * = nullptr>
constexpr unsigned int
get_communication_block_size(const VectorStruct &)
{
using local_element_t = decltype(std::declval<T const>().local_element(0));
template <typename T>
- using has_local_element = is_detected<local_element_t, T>;
+ constexpr bool has_local_element = is_supported_operation<local_element_t, T>;
decltype(std::declval<T>().add_local_element(0, typename T::value_type()));
template <typename T>
- using has_add_local_element = is_detected<add_local_element_t, T>;
+ constexpr bool has_add_local_element =
+ is_supported_operation<add_local_element_t, T>;
decltype(std::declval<T>().set_local_element(0, typename T::value_type()));
template <typename T>
- using has_set_local_element = is_detected<set_local_element_t, T>;
+ constexpr bool has_set_local_element =
+ is_supported_operation<set_local_element_t, T>;
std::declval<Utilities::MPI::Partitioner>()));
template <typename T>
- using has_partitioners_are_compatible =
- is_detected<partitioners_are_compatible_t, T>;
+ constexpr bool has_partitioners_are_compatible =
+ is_supported_operation<partitioners_are_compatible_t, T>;
using begin_t = decltype(std::declval<T const>().begin());
template <typename T>
- using has_begin = is_detected<begin_t, T>;
+ constexpr bool has_begin = is_supported_operation<begin_t, T>;
decltype(std::declval<T const>().shared_vector_data());
template <typename T>
- using has_shared_vector_data = is_detected<shared_vector_data_t, T>;
+ constexpr bool has_shared_vector_data =
+ is_supported_operation<shared_vector_data_t, T>;
struct is_vectorizable
{
static const bool value =
- has_begin<T>::value &&
- (has_local_element<T>::value ||
+ has_begin<T> &&
+ (has_local_element<T> ||
is_serial_vector<typename std::remove_const<T>::type>::value) &&
std::is_same<typename T::value_type, Number>::value;
};
decltype(std::declval<T const>().update_ghost_values_start(0));
template <typename T>
- using has_update_ghost_values_start =
- is_detected<update_ghost_values_start_t, T>;
+ constexpr bool has_update_ghost_values_start =
+ is_supported_operation<update_ghost_values_start_t, T>;
decltype(std::declval<T>().compress_start(0, VectorOperation::add));
template <typename T>
- using has_compress_start = is_detected<compress_start_t, T>;
+ constexpr bool has_compress_start =
+ is_supported_operation<compress_start_t, T>;
// We assume that if both begin() and local_element()
// exist, then begin() + offset == local_element(offset)
template <typename T>
- struct has_exchange_on_subset
- {
- static const bool value = has_begin<T>::value &&
- has_local_element<T>::value &&
- has_partitioners_are_compatible<T>::value;
- };
-
- // We need to have a separate declaration for static const members
- template <typename T>
- const bool has_exchange_on_subset<T>::value;
+ constexpr bool has_exchange_on_subset =
+ has_begin<T> &&has_local_element<T> &&has_partitioners_are_compatible<T>;
using communication_block_size_t = decltype(T::communication_block_size);
template <typename T>
- using has_communication_block_size =
- is_detected<communication_block_size_t, T>;
+ constexpr bool has_communication_block_size =
+ is_supported_operation<communication_block_size_t, T>;
template <class T>
using is_not_parallel_vector =
- detected_or_t<std::true_type, not_parallel_vector_t, T>;
+ SupportsOperation::detected_or_t<std::true_type, not_parallel_vector_t, T>;
} // namespace internal
#endif
// FIXME: this is wrong for Trilinos/Petsc MPI vectors
// where we should first do Partitioner::local_to_global()
template <typename VectorType,
- typename std::enable_if<!has_local_element<VectorType>::value,
+ typename std::enable_if<!has_local_element<VectorType>,
VectorType>::type * = nullptr>
inline typename VectorType::value_type
vector_access(const VectorType &vec, const unsigned int entry)
// FIXME: this is wrong for Trilinos/Petsc MPI vectors
// where we should first do Partitioner::local_to_global()
template <typename VectorType,
- typename std::enable_if<!has_local_element<VectorType>::value,
+ typename std::enable_if<!has_local_element<VectorType>,
VectorType>::type * = nullptr>
inline typename VectorType::value_type &
vector_access(VectorType &vec, const unsigned int entry)
// method to access data in local index space, which is what we use in
// DoFInfo and hence in read_dof_values etc.
template <typename VectorType,
- typename std::enable_if<has_local_element<VectorType>::value,
+ typename std::enable_if<has_local_element<VectorType>,
VectorType>::type * = nullptr>
inline typename VectorType::value_type &
vector_access(VectorType &vec, const unsigned int entry)
// same for const access
template <typename VectorType,
- typename std::enable_if<has_local_element<VectorType>::value,
+ typename std::enable_if<has_local_element<VectorType>,
VectorType>::type * = nullptr>
inline typename VectorType::value_type
vector_access(const VectorType &vec, const unsigned int entry)
template <typename VectorType,
- typename std::enable_if<has_add_local_element<VectorType>::value,
+ typename std::enable_if<has_add_local_element<VectorType>,
VectorType>::type * = nullptr>
inline void
vector_access_add(VectorType & vec,
template <typename VectorType,
- typename std::enable_if<!has_add_local_element<VectorType>::value,
+ typename std::enable_if<!has_add_local_element<VectorType>,
VectorType>::type * = nullptr>
inline void
vector_access_add(VectorType & vec,
template <typename VectorType,
- typename std::enable_if<has_add_local_element<VectorType>::value,
+ typename std::enable_if<has_add_local_element<VectorType>,
VectorType>::type * = nullptr>
inline void
vector_access_add_global(VectorType & vec,
template <typename VectorType,
- typename std::enable_if<!has_add_local_element<VectorType>::value,
+ typename std::enable_if<!has_add_local_element<VectorType>,
VectorType>::type * = nullptr>
inline void
vector_access_add_global(VectorType & vec,
template <typename VectorType,
- typename std::enable_if<has_set_local_element<VectorType>::value,
+ typename std::enable_if<has_set_local_element<VectorType>,
VectorType>::type * = nullptr>
inline void
vector_access_set(VectorType & vec,
template <typename VectorType,
- typename std::enable_if<!has_set_local_element<VectorType>::value,
+ typename std::enable_if<!has_set_local_element<VectorType>,
VectorType>::type * = nullptr>
inline void
vector_access_set(VectorType & vec,
// FIXME: this is incorrect for PETSc/Trilinos MPI vectors
template <
typename VectorType,
- typename std::enable_if<!has_partitioners_are_compatible<VectorType>::value,
+ typename std::enable_if<!has_partitioners_are_compatible<VectorType>,
VectorType>::type * = nullptr>
inline void
check_vector_compatibility(
// same as above for has_partitioners_are_compatible == true
- template <
- typename VectorType,
- typename std::enable_if<has_partitioners_are_compatible<VectorType>::value,
- VectorType>::type * = nullptr>
+ template <typename VectorType,
+ typename std::enable_if<has_partitioners_are_compatible<VectorType>,
+ VectorType>::type * = nullptr>
inline void
check_vector_compatibility(
const VectorType & vec,