From a1babbf2eee65ccd1c24896eec16b7f43a823783 Mon Sep 17 00:00:00 2001 From: Simon Praetorius Date: Sat, 21 Nov 2020 20:09:29 +0100 Subject: [PATCH 1/3] Add new detection function isValid --- amdis/AdaptiveGrid.hpp | 15 ++---- amdis/BoundaryManager.hpp | 9 ++-- amdis/ProblemStat.hpp | 3 -- amdis/ProblemStat.inc.hpp | 33 ++++--------- amdis/common/IsValid.hpp | 54 ++++++++++++++++++++++ amdis/functions/LocalView.hpp | 9 ++-- amdis/linearalgebra/VectorFacade.hpp | 11 +---- amdis/linearalgebra/istl/PreconWrapper.hpp | 7 +-- 8 files changed, 80 insertions(+), 61 deletions(-) create mode 100644 amdis/common/IsValid.hpp diff --git a/amdis/AdaptiveGrid.hpp b/amdis/AdaptiveGrid.hpp index 41e07080..9afe1b67 100644 --- a/amdis/AdaptiveGrid.hpp +++ b/amdis/AdaptiveGrid.hpp @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -402,9 +403,6 @@ namespace Dune hostFactory_.insertVertex(pos); } - template - using HasInsertElement = decltype(std::declval().insertElement(std::declval()...)); - /// Insert an element into the coarse grid void insertElement(GeometryType const& type, std::vector const& vertices) override @@ -429,10 +427,8 @@ namespace Dune ElementParametrizationType elementParametrization) override #endif { - using A0 = GeometryType; - using A1 = std::vector; - using A2 = ElementParametrizationType; - if constexpr (Std::is_detected::value) + auto hasInsertElement = isValid([](auto& hf, auto&& t, auto&& v, auto&& p) -> decltype(hf.insertElement(t,v,p)) {}); + if constexpr (hasInsertElement(hostFactory_, type, vertices, elementParametrization)) hostFactory_.insertElement(type, vertices, elementParametrization); else AMDiS::error_exit("insertElement() not implemented for HostGrid type."); @@ -454,9 +450,8 @@ namespace Dune void insertBoundarySegment(std::vector const& vertices, BoundarySegmentType const& boundarySegment) override { - using A0 = std::vector; - using A1 = BoundarySegmentType; - if constexpr (Std::is_detected::value) + auto hasInsertBoundarySegment = isValid([](auto& hf, auto&& v, auto&& bs) -> decltype(hf.insertBoundarySegment(v,bs)) {}); + if constexpr (hasInsertBoundarySegment(hostFactory_, vertices, boundarySegment)) hostFactory_.insertBoundarySegment(vertices, boundarySegment); else AMDiS::error_exit("insertBoundarySegment() not implemented for HostGrid type."); diff --git a/amdis/BoundaryManager.hpp b/amdis/BoundaryManager.hpp index 88009ad3..1d9f4423 100644 --- a/amdis/BoundaryManager.hpp +++ b/amdis/BoundaryManager.hpp @@ -8,6 +8,7 @@ #include #include +#include namespace AMDiS { @@ -135,13 +136,11 @@ namespace AMDiS } - template - using HasBoundaryId = decltype(std::declval().boundaryId()); - /// Set boundary ids as stored in the grid, e.g. read by grid reader void setBoundaryId() { - if (!Dune::Std::is_detected::value) + constexpr bool hasBoundaryId = isValid([](auto&& s)->decltype(s.boundaryId()){})(); + if (!hasBoundaryId) return; auto gv = grid_->leafGridView(); @@ -151,7 +150,7 @@ namespace AMDiS if (!segment.boundary()) continue; - if constexpr (Dune::Std::is_detected::value) { + if constexpr (hasBoundaryId) { auto index = segment.boundarySegmentIndex(); boundaryIds_[index] = segment.boundaryId(); } diff --git a/amdis/ProblemStat.hpp b/amdis/ProblemStat.hpp index bde021e4..f9c719c7 100644 --- a/amdis/ProblemStat.hpp +++ b/amdis/ProblemStat.hpp @@ -496,9 +496,6 @@ namespace AMDiS private: - void createGlobalBasisImpl(std::true_type); - void createGlobalBasisImpl(std::false_type); - void initGlobalBasis(); protected: diff --git a/amdis/ProblemStat.inc.hpp b/amdis/ProblemStat.inc.hpp index 659ec71d..c66adebb 100644 --- a/amdis/ProblemStat.inc.hpp +++ b/amdis/ProblemStat.inc.hpp @@ -175,25 +175,14 @@ using HasCreate = decltype(T::create(std::declval())); template void ProblemStat::createGlobalBasis() { - createGlobalBasisImpl(Dune::Std::is_detected{}); - initGlobalBasis(); -} - - -template -void ProblemStat::createGlobalBasisImpl(std::true_type) -{ - assert( bool(grid_) ); - static_assert(std::is_same_v, ""); - auto basis = Traits::create(name_, grid_->leafGridView()); - globalBasis_ = std::make_shared(std::move(basis)); -} - + if constexpr (Dune::Std::is_detected_v) { + assert( bool(grid_) ); + static_assert(std::is_same_v, ""); + globalBasis_ = std::make_shared(Traits::create(name_, grid_->leafGridView())); + } else + error_exit("Cannot create GlobalBasis from type. Pass a BasisCreator instead!"); -template -void ProblemStat::createGlobalBasisImpl(std::false_type) -{ - error_exit("Cannot create GlobalBasis from type. Pass a BasisCreator instead!"); + initGlobalBasis(); } @@ -416,17 +405,13 @@ globalCoarsen(int n) } -// grid has globalRefine(int, AdaptDataHandleInterface&) -template -using HasGlobalRefineADHI = decltype( - std::declval().globalRefine(1,std::declval())); - template Flag ProblemStat:: globalRefine(int n) { Dune::Timer t; - if constexpr (Dune::Std::is_detected::value) + auto hasGlobalRefineADHI = isValid([](auto& g, auto& callback) -> decltype(g.globalRefine(1,callback)){}); + if constexpr (hasGlobalRefineADHI()) grid_->globalRefine(n, globalBasis_->globalRefineCallback()); else grid_->globalRefine(n); diff --git a/amdis/common/IsValid.hpp b/amdis/common/IsValid.hpp new file mode 100644 index 00000000..32030141 --- /dev/null +++ b/amdis/common/IsValid.hpp @@ -0,0 +1,54 @@ +#pragma once + +namespace AMDiS { +namespace Impl { + +// helper class to check validity of an expression encoded in the +// functor F +template +struct IsValid +{ +private: + template + constexpr auto check(int) const noexcept + -> decltype(std::declval()(std::declval()..., std::declval()...), bool()) + { + return true; + } + + template + constexpr bool check(...) const noexcept + { + return false; + } + +public: + template + constexpr bool operator()(Args&&...) const noexcept + { + return check(int()); + } +}; + +} // end namespace Impl + +/// Utility to check whether a functor `F` can be invoked by given arguments. +/** + * This utility can be used for constexpr checks of validity of expressions. + * Thereby, the given functor must be usable in an unevaluated SFINAE context, + * i.e., provide the check in a trailing return-type. + * + * Example: +```c++ +auto hasResize = isValid([](auto& c) -> decltype(c.resize(10)) {}); +if constexpr( hasResize(container) ) + container.resize(10); +``` + **/ +template +constexpr auto isValid(F const&, Args&&...) +{ + return Impl::IsValid{}; +} + +} // end namespace AMDiS diff --git a/amdis/functions/LocalView.hpp b/amdis/functions/LocalView.hpp index 3570fd32..c41e9379 100644 --- a/amdis/functions/LocalView.hpp +++ b/amdis/functions/LocalView.hpp @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -45,10 +46,6 @@ namespace AMDiS /// Type used for global numbering of the basis vectors using MultiIndex = typename NodeIndexSet::MultiIndex; - private: - template - using hasIndices = decltype(std::declval().indices(std::declval>().begin())); - public: /// \brief Construct local view for a given global finite element basis LocalView (GlobalBasis const& globalBasis) @@ -74,7 +71,9 @@ namespace AMDiS nodeIndexSet_.bind(tree_); indices_.resize(size()); - if constexpr (Dune::Std::is_detected{}) + using Iter = TYPEOF(indices_.begin()); + auto hasIndices = isValid([](auto&& nis, auto&& it) -> std::void_t{}); + if constexpr (hasIndices()) nodeIndexSet_.indices(indices_.begin()); else for (size_type i = 0; i < size(); ++i) diff --git a/amdis/linearalgebra/VectorFacade.hpp b/amdis/linearalgebra/VectorFacade.hpp index 887f109f..e1ecdc89 100644 --- a/amdis/linearalgebra/VectorFacade.hpp +++ b/amdis/linearalgebra/VectorFacade.hpp @@ -71,17 +71,10 @@ namespace AMDiS Impl const& impl() const { return impl_; } Impl& impl() { return impl_; } - - template - using HasLocalSize = decltype(std::declval().localSize()); - - template - using HasGlobalSize = decltype(std::declval().globalSize()); - /// Return the number of entries in the local part of the vector std::size_t localSize() const { - if constexpr (Dune::Std::is_detected::value) + if constexpr (isValid([](auto&& impl) -> decltype(impl.localSize()){})()) return impl_.localSize(); else return impl_.size(); @@ -90,7 +83,7 @@ namespace AMDiS /// Return the number of entries in the global vector std::size_t globalSize() const { - if constexpr (Dune::Std::is_detected::value) + if constexpr (isValid([](auto&& impl) -> decltype(impl.globalSize()){})()) return impl_.globalSize(); else return impl_.size(); diff --git a/amdis/linearalgebra/istl/PreconWrapper.hpp b/amdis/linearalgebra/istl/PreconWrapper.hpp index e28766cf..8859de3f 100644 --- a/amdis/linearalgebra/istl/PreconWrapper.hpp +++ b/amdis/linearalgebra/istl/PreconWrapper.hpp @@ -27,10 +27,6 @@ namespace AMDiS using domain_type = typename P::domain_type; using range_type = typename P::range_type; - private: - template - using HasApplyFoward = decltype(std::declval().template apply(std::declval(), std::declval())); - public: template explicit PreconWrapper(Storage& storage, Args&&... args) @@ -60,7 +56,8 @@ namespace AMDiS template void apply(domain_type& v, range_type const& d) { - if constexpr (Dune::Std::is_detected::value) + auto hasApplyForward = isValid([](auto&& p) -> decltype(p.template apply(std::declval(), std::declval())){}); + if constexpr (hasApplyForward(precon_)) precon_.template apply(v,d); else precon_.apply(v,d); -- GitLab From c6e0a82e1e781796d642d9ec509c407d08e4aef9 Mon Sep 17 00:00:00 2001 From: Simon Praetorius Date: Sat, 21 Nov 2020 21:15:52 +0100 Subject: [PATCH 2/3] fix AdaptiveGrid --- amdis/AdaptiveGrid.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/amdis/AdaptiveGrid.hpp b/amdis/AdaptiveGrid.hpp index 9afe1b67..b85fbcad 100644 --- a/amdis/AdaptiveGrid.hpp +++ b/amdis/AdaptiveGrid.hpp @@ -427,7 +427,7 @@ namespace Dune ElementParametrizationType elementParametrization) override #endif { - auto hasInsertElement = isValid([](auto& hf, auto&& t, auto&& v, auto&& p) -> decltype(hf.insertElement(t,v,p)) {}); + auto hasInsertElement = AMDiS::isValid([](auto& hf, auto&& t, auto&& v, auto&& p) -> decltype(hf.insertElement(t,v,p)) {}); if constexpr (hasInsertElement(hostFactory_, type, vertices, elementParametrization)) hostFactory_.insertElement(type, vertices, elementParametrization); else -- GitLab From c0f3a3e090ad8fcaedd4762180a1331ed07615f6 Mon Sep 17 00:00:00 2001 From: Simon Praetorius Date: Sun, 22 Nov 2020 00:19:48 +0100 Subject: [PATCH 3/3] write macros to simplify instantiation of IS_VALID --- amdis/AdaptiveGrid.hpp | 20 ++--- amdis/BoundaryManager.hpp | 6 +- amdis/Marker.hpp | 5 +- amdis/MeshCreator.hpp | 28 ++++--- amdis/ProblemStat.inc.hpp | 4 +- amdis/common/IsValid.hpp | 86 ++++++++++++++++++---- amdis/functions/LocalView.hpp | 2 +- amdis/linearalgebra/VectorFacade.hpp | 4 +- amdis/linearalgebra/istl/PreconWrapper.hpp | 5 +- 9 files changed, 106 insertions(+), 54 deletions(-) diff --git a/amdis/AdaptiveGrid.hpp b/amdis/AdaptiveGrid.hpp index b85fbcad..fa857886 100644 --- a/amdis/AdaptiveGrid.hpp +++ b/amdis/AdaptiveGrid.hpp @@ -411,33 +411,29 @@ namespace Dune } #if DUNE_VERSION_LT(DUNE_GRID,2,8) - using ElementParametrizationType = std::shared_ptr,FieldVector > >; + using EPT = std::shared_ptr,FieldVector > >; /// Insert a parametrized element into the coarse grid void insertElement(GeometryType const& type, std::vector const& vertices, - ElementParametrizationType const& elementParametrization) override + EPT const& elementParametrization) override #else - using ElementParametrizationType - = std::function(FieldVector)>; + using EPT = std::function(FieldVector)>; /// Insert a parametrized element into the coarse grid void insertElement(GeometryType const& type, std::vector const& vertices, - ElementParametrizationType elementParametrization) override + EPT elementParametrization) override #endif { - auto hasInsertElement = AMDiS::isValid([](auto& hf, auto&& t, auto&& v, auto&& p) -> decltype(hf.insertElement(t,v,p)) {}); - if constexpr (hasInsertElement(hostFactory_, type, vertices, elementParametrization)) + auto hasInsertElement = AMDiS::isValid([](auto& hf, auto&&... args) -> decltype(hf.insertElement(args...)) {}); + if constexpr (hasInsertElement(type, vertices, elementParametrization)) hostFactory_.insertElement(type, vertices, elementParametrization); else AMDiS::error_exit("insertElement() not implemented for HostGrid type."); } using Super::insertElement; - template - using HasInsertBoundarySegment = decltype(std::declval().insertBoundarySegment(std::declval()...)); - //// Insert a boundary segment void insertBoundarySegment(std::vector const& vertices) override { @@ -450,8 +446,8 @@ namespace Dune void insertBoundarySegment(std::vector const& vertices, BoundarySegmentType const& boundarySegment) override { - auto hasInsertBoundarySegment = isValid([](auto& hf, auto&& v, auto&& bs) -> decltype(hf.insertBoundarySegment(v,bs)) {}); - if constexpr (hasInsertBoundarySegment(hostFactory_, vertices, boundarySegment)) + auto hasInsertBoundarySegment = AMDiS::isValid([](auto& hf, auto&&... args) -> decltype(hf.insertBoundarySegment(args...)) {}); + if constexpr (hasInsertBoundarySegment(vertices, boundarySegment)) hostFactory_.insertBoundarySegment(vertices, boundarySegment); else AMDiS::error_exit("insertBoundarySegment() not implemented for HostGrid type."); diff --git a/amdis/BoundaryManager.hpp b/amdis/BoundaryManager.hpp index 1d9f4423..99f3dd5b 100644 --- a/amdis/BoundaryManager.hpp +++ b/amdis/BoundaryManager.hpp @@ -139,8 +139,8 @@ namespace AMDiS /// Set boundary ids as stored in the grid, e.g. read by grid reader void setBoundaryId() { - constexpr bool hasBoundaryId = isValid([](auto&& s)->decltype(s.boundaryId()){})(); - if (!hasBoundaryId) + auto hasBoundaryId = IS_VALID(Segment)(_0.boundaryId()); + if (!hasBoundaryId()) return; auto gv = grid_->leafGridView(); @@ -150,7 +150,7 @@ namespace AMDiS if (!segment.boundary()) continue; - if constexpr (hasBoundaryId) { + if constexpr (hasBoundaryId()) { auto index = segment.boundarySegmentIndex(); boundaryIds_[index] = segment.boundaryId(); } diff --git a/amdis/Marker.hpp b/amdis/Marker.hpp index 91554bc0..fc176b2e 100644 --- a/amdis/Marker.hpp +++ b/amdis/Marker.hpp @@ -373,10 +373,7 @@ namespace AMDiS using Super = Marker; using Element = typename Super::Element; - template - using IsGridFunction = decltype(localFunction(std::declval())); - - static_assert(Dune::Std::is_detected::value, ""); + static_assert(IS_VALID(GridFct)(localFunction(_0))(), ""); public: /// Constructor. diff --git a/amdis/MeshCreator.hpp b/amdis/MeshCreator.hpp index c89fb352..304c1f9c 100644 --- a/amdis/MeshCreator.hpp +++ b/amdis/MeshCreator.hpp @@ -210,9 +210,6 @@ namespace AMDiS std::declval>(), std::declval >>()) ); - template - using SupportsInsertionIndex = decltype(std::declval>().insertionIndex(std::declval())); - // use GmshReader if GridFactory supports insertBoundarySegments template ::value)> @@ -223,25 +220,26 @@ namespace AMDiS std::vector boundaryIds, elementIds; reader.read(factory, filename, boundaryIds, elementIds); - using HasInsertionIndexEntity - = Dune::Std::is_detected::Entity>; - using HasInsertionIndexIntersection - = Dune::Std::is_detected; + using Element = typename GridType::template Codim<0>::Entity; + using Intersection = typename GridType::LeafIntersection; + + constexpr bool hasInsertionIndexEntity = IS_VALID(TYPEOF(factory),Element)(_0.insertionIndex(_1))(); + constexpr bool hasInsertionIndexIntersection = IS_VALID(TYPEOF(factory),Intersection)(_0.insertionIndex(_1))(); auto gridPtr = factory.createGrid(); if ((boundaryIds.empty() && elementIds.empty()) || - (!HasInsertionIndexEntity::value && !HasInsertionIndexIntersection::value)) + (!hasInsertionIndexEntity && !hasInsertionIndexIntersection)) return std::unique_ptr(std::move(gridPtr)); // map boundaryIds and elementIds read from file to grid indexing. - if (!boundaryIds.empty() && HasInsertionIndexIntersection::value) + if (!boundaryIds.empty() && hasInsertionIndexIntersection) boundaryIds_.resize(gridPtr->numBoundarySegments()); - if (!elementIds.empty() && HasInsertionIndexEntity::value) + if (!elementIds.empty() && hasInsertionIndexEntity) elementIds_.resize(gridPtr->size(0)); auto const& indexSet = gridPtr->leafIndexSet(); for (auto const& e : elements(gridPtr->leafGridView())) { - if constexpr(HasInsertionIndexEntity::value) { + if constexpr(hasInsertionIndexEntity) { if (!elementIds.empty()) elementIds_[indexSet.index(e)] = elementIds[factory.insertionIndex(e)]; } @@ -250,7 +248,7 @@ namespace AMDiS continue; for (auto const& it : intersections(gridPtr->leafGridView(), e)) { - if constexpr(HasInsertionIndexIntersection::value) { + if constexpr(hasInsertionIndexIntersection) { if (it.boundary()) boundaryIds_[it.boundarySegmentIndex()] = boundaryIds[factory.insertionIndex(it)]; @@ -273,12 +271,12 @@ namespace AMDiS #if HAVE_ALBERTA template - using IsAlbertaGrid = decltype(std::declval().alberta2dune(0,0)); + using IsAlbertaGrid = std::bool_constant; // construct the albertagrid directly from a filename template ::value)> + REQUIRES(IsAlbertaGrid::value)> std::unique_ptr read_alberta_file(std::string const& filename, Dune::PriorityTag<3>) const { return std::make_unique(filename); @@ -319,7 +317,7 @@ namespace AMDiS #if HAVE_ALBERTA // albertagrid -> simplex template ::value)> + REQUIRES(IsAlbertaGrid::value)> std::unique_ptr create_by_gridtype(Dune::PriorityTag<3>) const { return create_structured_grid([](auto&& lower, auto&& upper, auto&& numCells) diff --git a/amdis/ProblemStat.inc.hpp b/amdis/ProblemStat.inc.hpp index c66adebb..90ef1af9 100644 --- a/amdis/ProblemStat.inc.hpp +++ b/amdis/ProblemStat.inc.hpp @@ -410,8 +410,8 @@ Flag ProblemStat:: globalRefine(int n) { Dune::Timer t; - auto hasGlobalRefineADHI = isValid([](auto& g, auto& callback) -> decltype(g.globalRefine(1,callback)){}); - if constexpr (hasGlobalRefineADHI()) + auto hasGlobalRefineADH = IS_VALID(Grid&,int,typename GlobalBasis::ADH&)(_0.globalRefine(_1,_2)); + if constexpr (hasGlobalRefineADH()) grid_->globalRefine(n, globalBasis_->globalRefineCallback()); else grid_->globalRefine(n); diff --git a/amdis/common/IsValid.hpp b/amdis/common/IsValid.hpp index 32030141..8275d616 100644 --- a/amdis/common/IsValid.hpp +++ b/amdis/common/IsValid.hpp @@ -1,32 +1,37 @@ #pragma once +#include + namespace AMDiS { namespace Impl { // helper class to check validity of an expression encoded in the // functor F -template +template struct IsValid { private: - template - constexpr auto check(int) const noexcept - -> decltype(std::declval()(std::declval()..., std::declval()...), bool()) + // check whether the class arguments Args0... together with the function + // arguments (in that order) can be passed to the functor `F` + template + constexpr auto check (int) const noexcept + -> decltype(std::declval()(std::declval()..., std::declval()...), true) { return true; } - template - constexpr bool check(...) const noexcept + // faback implementation in case the trailing return type results in a substitution failure + template + constexpr bool check (...) const noexcept { return false; } public: - template - constexpr bool operator()(Args&&...) const noexcept + template + constexpr bool operator() (Args1&&...) const noexcept { - return check(int()); + return check(0); } }; @@ -38,17 +43,72 @@ public: * Thereby, the given functor must be usable in an unevaluated SFINAE context, * i.e., provide the check in a trailing return-type. * - * Example: + * Example1: + * Either you pass the parameters to check in the expression as arguments to the + * creates IsValid functor: ```c++ auto hasResize = isValid([](auto& c) -> decltype(c.resize(10)) {}); if constexpr( hasResize(container) ) container.resize(10); ``` + * or pass the types of the parameters as template parameters to isValid: +```c++ +auto hasResize = isValid([](auto& c) -> decltype(c.resize(10)) {}); +if constexpr( hasResize() ) + container.resize(10); +``` + * Note, template and function parameters are combined to the full parameter + * list of the lambda expression that is passed in to isValid. **/ -template -constexpr auto isValid(F const&, Args&&...) +template +constexpr auto isValid (F const&) { - return Impl::IsValid{}; + return Impl::IsValid{}; } + +// definition of IS_VALID macros with up to 10 arguments +#define IS_VALID_0() \ + AMDiS::isValid([]() constexpr -> IS_VALID_EXPANDER_END +#define IS_VALID_1(...) \ + AMDiS::isValid<__VA_ARGS__>([](auto&& _0) constexpr -> IS_VALID_EXPANDER_END +#define IS_VALID_2(...) \ + AMDiS::isValid<__VA_ARGS__>([](auto&& _0,auto&& _1) constexpr -> IS_VALID_EXPANDER_END +#define IS_VALID_3(...) \ + AMDiS::isValid<__VA_ARGS__>([](auto&& _0,auto&& _1,auto&& _2) constexpr -> IS_VALID_EXPANDER_END +#define IS_VALID_4(...) \ + AMDiS::isValid<__VA_ARGS__>([](auto&& _0,auto&& _1,auto&& _2,auto&& _3) constexpr -> IS_VALID_EXPANDER_END +#define IS_VALID_5(...) \ + AMDiS::isValid<__VA_ARGS__>([](auto&& _0,auto&& _1,auto&& _2,auto&& _3,auto&& _4) constexpr -> IS_VALID_EXPANDER_END +#define IS_VALID_6(...) \ + AMDiS::isValid<__VA_ARGS__>([](auto&& _0,auto&& _1,auto&& _2,auto&& _3,auto&& _4,auto&& _5) constexpr -> IS_VALID_EXPANDER_END +#define IS_VALID_7(...) \ + AMDiS::isValid<__VA_ARGS__>([](auto&& _0,auto&& _1,auto&& _2,auto&& _3,auto&& _4,auto&& _5,auto&& _6) constexpr -> IS_VALID_EXPANDER_END +#define IS_VALID_8(...) \ + AMDiS::isValid<__VA_ARGS__>([](auto&& _0,auto&& _1,auto&& _2,auto&& _3,auto&& _4,auto&& _5,auto&& _6,auto&& _7) constexpr -> IS_VALID_EXPANDER_END +#define IS_VALID_9(...) \ + AMDiS::isValid<__VA_ARGS__>([](auto&& _0,auto&& _1,auto&& _2,auto&& _3,auto&& _4,auto&& _5,auto&& _6,auto&& _7,auto&& _8) constexpr -> IS_VALID_EXPANDER_END +#define IS_VALID_10(...) \ + AMDiS::isValid<__VA_ARGS__>([](auto&& _0,auto&& _1,auto&& _2,auto&& _3,auto&& _4,auto&& _5,auto&& _6,auto&& _7,auto&& _8,auto&& _9) constexpr -> IS_VALID_EXPANDER_END + +#define IS_VALID_EXPANDER_END(...) decltype(__VA_ARGS__, true) { return true; }) + +// helper macro to select the given overload based on the number of arguments passed +#define SELECT_OVERRIDE(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, NAME, ...) NAME + +/// Macro to be called is shortcut for the manual definition of the lambda functions +/** + * Defines the lambda by introducing arguments with placeholder names _0, _1, _2, ... + * in the order of the types passed to the IS_VALID macro. + * + * Example of usage: +```c++ +auto hasResize = IS_VALID(Container&)(_0.resize(10)); +if constexpr( hasResize() ) + container.resize(10); +``` + **/ +#define IS_VALID(...) SELECT_OVERRIDE(__VA_ARGS__, _DUMMY, \ + IS_VALID_10,IS_VALID_9,IS_VALID_8,IS_VALID_7,IS_VALID_6,IS_VALID_5,IS_VALID_4,IS_VALID_3,IS_VALID_2,IS_VALID_1,IS_VALID_0)(__VA_ARGS__) + } // end namespace AMDiS diff --git a/amdis/functions/LocalView.hpp b/amdis/functions/LocalView.hpp index c41e9379..0dd63923 100644 --- a/amdis/functions/LocalView.hpp +++ b/amdis/functions/LocalView.hpp @@ -72,7 +72,7 @@ namespace AMDiS indices_.resize(size()); using Iter = TYPEOF(indices_.begin()); - auto hasIndices = isValid([](auto&& nis, auto&& it) -> std::void_t{}); + auto hasIndices = IS_VALID(NodeIndexSet,Iter)(_0.indices(_1)); if constexpr (hasIndices()) nodeIndexSet_.indices(indices_.begin()); else diff --git a/amdis/linearalgebra/VectorFacade.hpp b/amdis/linearalgebra/VectorFacade.hpp index e1ecdc89..fa744df6 100644 --- a/amdis/linearalgebra/VectorFacade.hpp +++ b/amdis/linearalgebra/VectorFacade.hpp @@ -74,7 +74,7 @@ namespace AMDiS /// Return the number of entries in the local part of the vector std::size_t localSize() const { - if constexpr (isValid([](auto&& impl) -> decltype(impl.localSize()){})()) + if constexpr (IS_VALID(Impl)(_0.localSize())()) return impl_.localSize(); else return impl_.size(); @@ -83,7 +83,7 @@ namespace AMDiS /// Return the number of entries in the global vector std::size_t globalSize() const { - if constexpr (isValid([](auto&& impl) -> decltype(impl.globalSize()){})()) + if constexpr (IS_VALID(Impl)(_0.globalSize())()) return impl_.globalSize(); else return impl_.size(); diff --git a/amdis/linearalgebra/istl/PreconWrapper.hpp b/amdis/linearalgebra/istl/PreconWrapper.hpp index 8859de3f..cb4312b9 100644 --- a/amdis/linearalgebra/istl/PreconWrapper.hpp +++ b/amdis/linearalgebra/istl/PreconWrapper.hpp @@ -10,6 +10,7 @@ #include #include +#include #include namespace AMDiS @@ -56,8 +57,8 @@ namespace AMDiS template void apply(domain_type& v, range_type const& d) { - auto hasApplyForward = isValid([](auto&& p) -> decltype(p.template apply(std::declval(), std::declval())){}); - if constexpr (hasApplyForward(precon_)) + auto hasApplyForward = IS_VALID(P&, domain_type&, range_type)(_0.template apply(_1, _2)); + if constexpr (hasApplyForward()) precon_.template apply(v,d); else precon_.apply(v,d); -- GitLab