Adjust transform_iterator constructors for default constructability checks
The transform_iterator constructor has the potential to cause problems for checks of default constructability (and different results for different compilers clang vs gcc).
This PR makes clear to the compiler exactly when the transform_iterator is default constructible, where other simpler versions with default arguments or without the enable_if may result in build errors or the wrong value being returned when std::is_default_constructible is called on the transform_iterator.
This PR changes transform_iterator in that it only enables the constructors which are valid in the instantiation by separating out the constructors which rely upon default constructors of the template types, and only enabling them under the correct circumstances of default constructability of template arguments.
This is a better fix for the issue which motivated #1432. However, I think both are changes for the better.
Update: The PR has grown to include:
- Changes to constructors of
transform_iteratorto enable default constructability checks - removal of
constfrom the unary functor withintransform_iterator - new utility:
__is_const_callable_with_arg_v - testing changes to match changes in code and test fixed functionality
- documentation changes to be more explicit about eligible functors for use with
transform_iterator
So, this change has an consequence...
LegacyForwardIterator and therefore LegacyBidirectionalIterator and LegacyRandomAccessIterator requires default constructible.
The way transform_iterator was written, it was returning true for is_default_constructible even when it was not the case (lambdas are not default constructible in C++17). Now it accurately returns false when the unary functor is not default constructible.
Practically, we may not have an issue here, other with our tests which are static_assert default constructible. We need to consider the consequences of this change though. Within transform_iterator, we carry forward the iterator category from the source iterator, regardless of the functor.
The clang format suggestion is a bug in clang format where it mistakes a binary AND for a rvalue reference. It is intentionally ignored.
Thanks all for the reviews! Very interesting investigation I think, and I like where it ended up.