An Eigen 3.4 2x2 matrix has a begin member function that returns void and a static_assert that evaluates to false (as you're not meant to call begin on a non-1d matrix).
However this doesn't play nicely with the SFINAE checks at the moment in fmt as they simply perform a SFINAE check that the expression T{}.begin() is valid, which evaluating to void is (even though it's of course not a valid type for an iterator):
To model a range more strictly to eliminate this case:
If we look at the c++20 concept for a range, it requires ranges::begin on the type, and that requires the iterator type satisfy input_or_output_iterator, which specifically notes that begin returns: The exposition-only concept /*can-reference*/ is satisfied if and only if the type is referenceable (in particular, not void).
So just check we can deref the result of that type to fix this case, and not incorrectly identify a type with void begin/end functions as a range. Note we don't want to do this for the type returned by end, as (in c++ >= 20) it may be a different sentinel type that is not dereferenceable
Fixes issue #3839
An Eigen 3.4 2x2 matrix has a begin member function that returns void and a static_assert that evaluates to false (as you're not meant to call begin on a non-1d matrix). However this doesn't play nicely with the SFINAE checks at the moment in fmt as they simply perform a SFINAE check that the expression
T{}.begin()
is valid, which evaluating tovoid
is (even though it's of course not a valid type for an iterator):https://github.com/fmtlib/fmt/blob/75e892420ed84a058f0a494d693a6baf5212eac4/include/fmt/ranges.h#L100-L104
To model a range more strictly to eliminate this case:
If we look at the c++20 concept for a range, it requires
ranges::begin
on the type, and that requires the iterator type satisfy input_or_output_iterator, which specifically notes thatbegin
returns:The exposition-only concept /*can-reference*/ is satisfied if and only if the type is referenceable (in particular, not void).
So just check we can deref the result of that type to fix this case, and not incorrectly identify a type with
void begin/end
functions as a range. Note we don't want to do this for the type returned byend
, as (in c++ >= 20) it may be a different sentinel type that is not dereferenceable