Loading...
Searching...
No Matches
concept.hh
Go to the documentation of this file.
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
// SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root
// SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception
#ifndef DUNE_COMMON_CONCEPT_HH
#define DUNE_COMMON_CONCEPT_HH
#include <type_traits>
#include <utility>
#include <tuple>
#include <dune/common/typeutilities.hh>
#include <dune/common/typelist.hh>
#include <dune/common/indices.hh>
namespace Dune {
namespace Concept {
template<class... BaseConcepts>
struct Refines
{
typedef TypeList<BaseConcepts...> BaseConceptList;
};
#ifndef DOXYGEN
namespace Impl {
// #############################################################################
// # All functions following here are implementation details
// # for the models() function below.
// #############################################################################
// Forward declaration
template<class C, class... T>
constexpr bool models();
// Here is the implementation of the concept checking.
// The first two overloads do the magic for checking
// if the requirements of a concept are satisfied.
// The rest is just for checking base concepts in case
// of refinement.
// This overload is present if type substitution for
// C::require(T...) is successful, i.e., if the T...
// matches the requirement of C. In this case this
// overload is selected because PriorityTag<1>
// is a better match for PrioriryTag<42> than
// PriorityTag<0> in the default overload.
template<class C, class... T,
decltype(std::declval<C>().require(std::declval<T>()...), 0) =0>
constexpr std::true_type matchesRequirement(PriorityTag<1>)
{ return {}; }
// If the above overload is ruled out by SFINAE because
// the T... does not match the requirements of C, then
// this default overload drops in.
template<class C, class... T>
constexpr std::false_type matchesRequirement(PriorityTag<0>)
{ return {}; }
// An empty list C of concepts is always matched by T...
template<class...T>
constexpr bool modelsConceptList(TypeList<>)
{ return true; }
// A nonempty list C0,..,CN of concepts is modeled
// by T... if it models the concept C0
// and all concepts in the list C1,..,CN.
template<class...T, class C0, class... CC>
constexpr bool modelsConceptList(TypeList<C0, CC...>)
{ return models<C0, T...>() and modelsConceptList<T...>(TypeList<CC...>()); }
// If C is an unrefined concept, then T... models C
// if it matches the requirement of C.
template<class C, class... T>
constexpr bool modelsConcept(PriorityTag<0>)
{ return matchesRequirement<C, T...>(PriorityTag<42>()); }
// If C is a refined concept, then T... models C
// if it matches the requirement of C and of
// all base concepts.
//
// This overload is used if C::BaseConceptList exists
// due to its higher priority.
template<class C, class... T,
decltype(typename C::BaseConceptList(), 0) = 0>
constexpr bool modelsConcept(PriorityTag<1>)
{ return matchesRequirement<C, T...>(PriorityTag<42>()) and modelsConceptList<T...>(typename C::BaseConceptList()); }
// This is the full concept check. It's defined here in the
// implementation namespace with 'constexpr bool' return type
// because we need a forward declaration in order to use it
// internally above.
//
// The actual interface function can then call this one and
// return the result as std::integral_constant<bool,*> which
// does not allow for a forward declaration because the return
// type is deduced.
template<class C, class... T>
constexpr bool models()
{
return modelsConcept<C, T...>(PriorityTag<42>());
}
} // namespace Dune::Concept::Impl
#endif // DOXYGEN
} // namespace Dune::Concept
template<class C, class... T>
constexpr auto models()
{
return std::bool_constant<Concept::Impl::models<C, T...>()>();
}
namespace Concept {
// #############################################################################
// # The method tupleEntriesModel() does the actual check if the types in a tuple
// # model a concept using the implementation details above.
// #############################################################################
template<class C, class Tuple>
constexpr auto tupleEntriesModel()
{
return Dune::unpackIntegerSequence([&](auto... i) {
return std::conjunction<decltype(Dune::models<C, std::tuple_element_t<decltype(i)::value, Tuple>>())...>();
}, std::make_index_sequence<std::tuple_size_v<Tuple>>());
}
// #############################################################################
// # The following require*() functions are just helpers that allow to
// # propagate a failed check as substitution failure. This is useful
// # inside of a concept definition.
// #############################################################################
// Helper function for use in concept definitions.
// If the passed value b is not true, the concept will to be satisfied.
template<bool b, typename std::enable_if<b, int>::type = 0>
constexpr bool requireTrue()
{
return true;
}
// Helper function for use in concept definitions.
template<class C, class... T, typename std::enable_if<models<C, T...>(), int>::type = 0>
constexpr bool requireConcept()
{
return true;
}
// Helper function for use in concept definitions.
// This allows to avoid using decltype
template<class C, class... T, typename std::enable_if<models<C, T...>(), int>::type = 0>
constexpr bool requireConcept(T&&... /*t*/)
{
return true;
}
// Helper function for use in concept definitions.
// This checks if the concept given as first type is modelled by all types in the tuple passed as argument
template<class C, class Tuple, typename std::enable_if<tupleEntriesModel<C, Tuple>(), int>::type = 0>
constexpr bool requireConceptForTupleEntries()
{
return true;
}
// Helper function for use in concept definitions.
// If the first passed type is not convertible to the second, the concept will not be satisfied.
template<class From, class To,
typename std::enable_if< std::is_convertible<From, To>::value, int>::type = 0>
constexpr bool requireConvertible()
{
return true;
}
// Helper function for use in concept definitions.
// If passed argument is not convertible to the first passed type, the concept will not be satisfied.
template<class To, class From,
typename std::enable_if< std::is_convertible<From, To>::value, int>::type = 0>
constexpr bool requireConvertible(const From&)
{
return true;
}
// Helper function for use in concept definitions.
// This will always evaluate to true. If just allow
// to turn a type into an expression. The failure happens
// already during substitution for the type argument.
template<typename T>
constexpr bool requireType()
{
return true;
}
// Helper function for use in concept definitions.
// If first passed type is not a base class of second type, the concept will not be satisfied.
template<class Base, class Derived,
typename std::enable_if< std::is_base_of<Base, Derived>::value, int>::type = 0>
constexpr bool requireBaseOf()
{
return true;
}
// Helper function for use in concept definitions.
// If first passed type is not a base class of first arguments type, the concept will not be satisfied.
template<class Base, class Derived,
typename std::enable_if< std::is_base_of<Base, Derived>::value, int>::type = 0>
constexpr bool requireBaseOf(const Derived&)
{
return true;
}
// Helper function for use in concept definitions.
// If the passed types are not the same, the concept will not be satisfied.
template<class A, class B,
typename std::enable_if< std::is_same<A, B>::value, int>::type = 0>
constexpr bool requireSameType()
{
return true;
}
} // namespace Dune::Concept
} // namespace Dune
#endif // DUNE_COMMON_CONCEPT_HH
typelist.hh
typeutilities.hh
Utilities for type computations, constraining overloads, ...
indices.hh
Dune::unpackIntegerSequence
decltype(auto) constexpr unpackIntegerSequence(F &&f, std::integer_sequence< I, i... > sequence)
Unpack an std::integer_sequence<I,i...> to std::integral_constant<I,i>...
Definition indices.hh:124
Dune::TypeList
std::tuple< MetaType< T >... > TypeList
A simple type list.
Definition typelist.hh:87
Dune::models
constexpr auto models()
Check if concept is modeled by given types.
Definition concept.hh:183
Dune
Dune namespace
Definition alignedallocator.hh:13
Dune::Concept
Namespace for concepts.
Definition concept.hh:33
Dune::Concept::requireConcept
constexpr bool requireConcept()
Definition concept.hh:221
Dune::Concept::requireTrue
constexpr bool requireTrue()
Definition concept.hh:214
Dune::Concept::requireSameType
constexpr bool requireSameType()
Definition concept.hh:292
Dune::Concept::requireConceptForTupleEntries
constexpr bool requireConceptForTupleEntries()
Definition concept.hh:237
Dune::Concept::requireBaseOf
constexpr bool requireBaseOf()
Definition concept.hh:274
Dune::Concept::requireConvertible
constexpr bool requireConvertible()
Definition concept.hh:246
Dune::Concept::tupleEntriesModel
constexpr auto tupleEntriesModel()
Definition concept.hh:198
Dune::Concept::requireType
constexpr bool requireType()
Definition concept.hh:265
Dune::Concept::Refines
Base class for refined concepts.
Definition concept.hh:53
Dune::Concept::Refines::BaseConceptList
TypeList< BaseConcepts... > BaseConceptList
Definition concept.hh:54
Dune::type
Dune::PriorityTag
Helper class for tagging priorities.
Definition typeutilities.hh:73