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
Be more generous in what types we allow in the FESystem(...) constructor #5090
Conversation
See also #4249. |
Nice. That looks easier than expected. I am bit surpised that this actually compiles for you. since the universal reference just matches everything. In particular, all the places where the old constructors are used are problematic and I get lots of compile errors using Hence, I think that you have to go back to some |
Regarding your change in
telling me that the second argument has to be a rvalue reference. |
Adding to the last comment, cppreference says that |
I see the issue with the compile error as well now. I apparently only verified with the tests that actually use the variadic constructor. Will fix. |
What a bizarre definition of |
OK, this should work now. Can you take another look? I had to work a bit with additional classes such as |
@@ -25,10 +25,26 @@ | |||
|
|||
DEAL_II_NAMESPACE_OPEN | |||
|
|||
namespace | |||
namespace internal |
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.
why don't you like the anonymous namespace here?
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.
i think @drwells was recently fixing those, i.e. adding internal
to anonymous namespaces. I forgot the reason, though 😄
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.
Anonymous namespaces in header files are generally a not so great idea.
An anonymous namespace is equivalent to a named namespace where the name is automatically created for each "translation unit" (i.e., .cc file that #include
s the header). That means that a symbol in an anonymous namespace in a header file is distinct between two object files. Most of the time this has no practical impact other than the fact that the linker cannot, for example, unify the code for one function. But you'd get into trouble if you had, for example, a global variable in such a namespace, or maybe a static
variable in a function in such a namespace: these variables are not in fact global, but duplicated in every .cc file that #include
s the header file.
For such reasons, it's generally not a great idea to use anonymous namespaces in header files. Most of the time, nothing bad happens, but when something bad happens, it's a really bizarre situation that difficult to debug.
}; | ||
|
||
|
||
/* | ||
* A generalization of `std::enable` that only works if |
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.
std::enable
-> std::enable_if
*/ | ||
template <class Type, class... Types> | ||
struct all_same_as | ||
{ | ||
static constexpr bool value = | ||
std::is_same<BoolStorage<std::is_same<Type, Types>::value..., true>, | ||
BoolStorage<true, std::is_same<Type, Types>::value...>>::value; | ||
internal::TemplateConstraints::all_true<std::is_same<Type, Types>::value...>::value; | ||
}; | ||
|
||
|
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.
This should be three blank lines, shouldn't it?
{ | ||
// helper struct for is_base_of_all and all_same_as | ||
template <bool... Types> struct BoolStorage; | ||
namespace TemplateConstraints |
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.
This would probably a good namespace name for everything in this file... Again, I don't quite see the need for a named namespace here.
include/deal.II/fe/fe_system.h
Outdated
template <class... FEPairs, | ||
typename = typename enable_if_all< | ||
(std::is_same<std::pair<std::unique_ptr<FiniteElement<dim, spacedim>>, unsigned int>, | ||
typename std::decay<FEPairs>::type>::value |
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.
Don't we normally test using syntax like
x==1
instead of 1==x
?
* true. | ||
*/ | ||
template <bool... Values> | ||
struct enable_if_all : std::enable_if<internal::TemplateConstraints::all_true<Values...>::value> |
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.
For this to be analogous to std::enable_if
I would expect to be able to specify a type (default void
) I can access via std::enable_if_all<...>::type
if all of the statements are true. Can you add this?
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.
Well, that's sort of a problem. I had tried that, but to be analogous to std::enable_if
, I would have to declare this as
template <bool... Values,
typename T = void>
struct enable_if_all : std::enable_if<..., T> {};
But that's not allowed: parameter packs must appear at the end of the template argument list. So my only choice would have been to move T
to be the first argument, and then I can't give it a default value.
So, I didn't know what to do and went with the easy path which was to omit T
altogether. I couldn't come up with a better solution. What do you think the best approach is, @masterleinad ?
include/deal.II/fe/fe_system.h
Outdated
@@ -1147,17 +1167,42 @@ namespace | |||
return fe_system.second > 0; | |||
}); | |||
} | |||
|
|||
|
|||
template <int dim, int spacedim> |
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.
Also three blank lines.
Apart from the things I commented on, I really like this. |
Specifically, include the one that is necessary for std::enable_if.
While there, simplify some other classes a bit by introducing an 'all_true' class. Also move classes into a named internal namespace.
I think I addressed all of the issues other than the |
What about about the following?
edit: default type parameter |
Hm, I tried this, but I can't seem to make it work. Does the patch you propose above actually work for you, including all of the existing and new tests? |
Using
in |
I tried this again but it doesn't seem to work with GCC 4.8. This may well be a compiler bug in C++11 support. The errors are like this:
In other words, SFINAE doesn't seem to actually work here. How do you want to proceed? We don't actually need the nested type, so the current |
Let's just stick with the current version. We can alyways extend |
/run-tests |
Thanks! |
This is a follow-up to the new variadic constructor of
FESystem
introduced in #5026: We now allow the argument list to be composed of either (i) pairs of a pointer to finite element and multiplicity, or (ii) just finite element. This allows writing things such aswhere the second argument has no multiplicity.
This works by routing each argument to a function
promote_to_pair()
that just forwards the original pair if it really is a pair, or that creates a pair of that element and multiplicity one if it is not a pair.The last commit extends this a bit by adding another function
promote_to_pair()
that just eats all other possible argument types but has astatic_assert
that explains in detail that you can't do that. For example, if you pass an integer as an argument, you'd get this sort of error message:There is a new test,
system_04
that is a variation ofsystem_03
that just omits the^1
cases. The output is identical to the previous test.