New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Play with C++20 concepts #14836
Play with C++20 concepts #14836
Conversation
7d780ef
to
956990f
Compare
@@ -150,6 +150,18 @@ | |||
#cmakedefine DEAL_II_HAVE_CXX17 | |||
#cmakedefine DEAL_II_HAVE_CXX20 | |||
|
|||
/** | |||
* If we have C++20 available, we can have concepts and requires |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably check that we define DEAL_II_HAVE_CXX20 only if the compiler supports concepts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean to exclude compilers that have a -std=c++20
command line flag, but do not actually support all of C++20?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, adding something using concepts in cmake/checks/check_01_cxx_features.cmake.
include/deal.II/base/config.h.in
Outdated
@@ -150,6 +150,18 @@ | |||
#cmakedefine DEAL_II_HAVE_CXX17 | |||
#cmakedefine DEAL_II_HAVE_CXX20 | |||
|
|||
/** | |||
* If we have C++20 available, we can have concepts and requires | |||
* clauses. We want to avoid using too many #ifdef statements, so |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doxygen
doesn't like #ifdef here.
I added a check for |
// Test concepts and requires clauses | ||
template <int dim, int spacedim> | ||
concept is_valid_dim_spacedim = (dim >= 1 && spacedim <= 3 && | ||
dim <= spacedim); | ||
|
||
template <int dim, int spacedim> | ||
requires is_valid_dim_spacedim<dim,spacedim> | ||
class Triangulation | ||
{}; | ||
|
||
Triangulation<1,3> t; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Test concepts and requires clauses | |
template <int dim, int spacedim> | |
concept is_valid_dim_spacedim = (dim >= 1 && spacedim <= 3 && | |
dim <= spacedim); | |
template <int dim, int spacedim> | |
requires is_valid_dim_spacedim<dim,spacedim> | |
class Triangulation | |
{}; | |
Triangulation<1,3> t; | |
#if !(defined __cpp_concepts) || (__cpp_concepts < 201907L) | |
# error \"insufficient support for C++20\" | |
#endif |
for conformity (might also be slightly faster).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, I actually would like to keep it as is. If we don't trust that -std=c++20
works, then we also shouldn't trust that __cpp_concepts
is set correctly. Let's test for the actual feature we want to use.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The point of these CMake
features check really is that we decide if C++20 is supported based on the capabilities of the compilers with the given flags and not because the user requested C++20 support in any other way (at the moment). Thus, I wouldn't say that we don't trust that -std=c++20
works (since compilers allow passing this flag without supporting all of C++20 anyway). On the other hand, I think that the __cpp_concepts
feature check is reliable, though. Anyway, I rather wanted to suggest using that than requesting changes.
Such a good idea! |
I like this direction. |
I just merged it 😄 |
Well, I had assumed that this would generate more discussion :-) I'll plod along and add some annotations to functions on occasion then! |
Part of #14840. |
A while ago, we had a mail on the forum where someone got a linker error that turned out to be rather difficult to figure out. Ultimately, what happened is that they called a
VectorTools
function with many arguments from aconst
member function, which made the type of the solution vector aconst Vector
, which the compiler gladly accepted as a valid template argument -- alas, we did of course not instantiate the function with aconst
type because the argument was supposed to be writable.That made me think about how we could avoid this kind of thing. The long-term solution is to use C++20 concepts that would annotate this function with a
clause. If that clause had been there, the compiler would have provided an error message of the sort
That would have at least produced a compiler (rather than linker) error that is modestly helpful in finding the issue.
This patch is an attempt at playing with C++20 concepts a bit. Everything is guarded by
#ifdef DEAL_II_HAVE_CXX20
, so nothing should be visible to compilers that don't enable this. For the moment, I haven't gone all in at annotating things, but only trialled the following classes:dim>=1, spacedim<=3, dim<=spacedim
dim>=0
.In reality, I don't think that all that many classes need to be annotated with
requires
clauses because in many cases we keep passing objects around. IfSolutionTransfer
takes aDoFHandler
as template argument, then the constraints onDoFHandler
automatically carry over toSolutionTransfer
: You can't instantiateSolutionTransfer<DoFHandler<3,2>>
because you can't instantiateDoFHandler
. Whether we do or do not annotateSolutionTransfer
is then more a matter of taste or documentation.In any case, I'm not trying to be comprehensive here, but am looking for feedback on whether that's a direction worth going. My personal opinion is that it is, in parts because we know that we want to use C++20 anyway in a few years. As an illustration of the usefulness of the general idea, I present #14828 and #14832, which are cases where we violated the constraints I had attached to
Triangulation
in specific instantiations.