-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
Supporting nested format specs for ranges. #2673
Conversation
include/fmt/ranges.h
Outdated
using context = buffer_context<Char>; | ||
using mapper = detail::arg_mapper<context>; | ||
using element = detail::uncvref_type<R>; | ||
|
||
template <typename T, | ||
FMT_ENABLE_IF(has_formatter<remove_cvref_t<T>, context>::value)> | ||
static auto map(T&& value) -> T&& { | ||
return (T &&) value; | ||
} | ||
template <typename T, | ||
FMT_ENABLE_IF(!has_formatter<remove_cvref_t<T>, context>::value)> | ||
static auto map(T&& value) -> decltype(mapper().map((T &&) value)) { | ||
return mapper().map((T &&) value); | ||
} | ||
|
||
using formatter_type = conditional_t< | ||
is_formattable<element, Char>::value, | ||
formatter<remove_cvref_t<decltype(map(std::declval<element>()))>, Char>, | ||
detail::fallback_formatter<element, Char>>; | ||
formatter_type underlying_; |
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 more or less copied this from join
, but I feel like there's probably a more direct way of getting the right formatter_type
?
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.
Not if we want to support implicit conversions. I suggest moving it to a new trait in detail
and using in both places.
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.
Thanks for the PR! Overall looks good but please address the inline comments.
include/fmt/ranges.h
Outdated
@@ -229,7 +229,7 @@ template <class Tuple, class F> void for_each(Tuple&& tup, F&& f) { | |||
} | |||
|
|||
template <typename Range> | |||
using value_type = | |||
using uncvref_type = |
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 value_type
is more descriptive because this gives the range value type. The fact that cvref is removed is less important.
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.
It doesn't give the value_type
though, it gives you the range's reference
- with cvref stripped. A lot of the time, that is the value_type
, but not always. For example: for vector<bool>
the value_type
is bool
but this gives you vector<bool>::reference
(which is what we would actually use to format). Or zip
ping two vector<int>
s has a value_type
of pair<int, int>
but this gives you pair<int&, int&>
.
I wanted to change it mainly because calling it value_type
is misleading - we never use the range's value_type
for anything.
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.
OK but could you clarify this in the comment then?
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.
Sure.
Uh, I'm failing CI because of... throwing exceptions? I don't understand. |
cdfd111
to
8b681f1
Compare
Not sure what you are referring to but the error is
|
@phprus pointed out that it was because I was doing This one I don't understand. Only fails on Windows too? |
Looks like on MSVC the |
This seems like an MSVC bug. Here's an example: #include <utility>
namespace fmt2 {
template <typename T, size_t N>
auto range_begin(T(&)[N]) -> T*;
template <typename R>
using iterator_t = decltype(range_begin(std::declval<R&>()));
template <typename R>
using reference_t = decltype(*std::declval<iterator_t<R>&>());
}
using R = int[3][2];
static_assert(
std::is_same_v<
fmt2::iterator_t<R>, int(*)[2]
>,
"!"
);
static_assert(
std::is_same_v<
fmt2::reference_t<R>, int(&)[2]
>,
"!"
); The reference type of If it's just arrays, I guess could add special handling for arrays for MSVC? This is probably the same bug that you were already working around in this space: // Workaround a bug in MSVC 2019 and earlier. |
9b636f6
to
8a04ce1
Compare
I got an email about checks failing, but it looks like all the checks passed? I don't even know. |
Merged, thanks! |
@brevzin could you by any chance add a section documenting this new feature (similarly to https://github.com/fmtlib/fmt/blob/master/doc/syntax.rst#chrono-format-specifications)? |
Basic support for nested formatters for ranges from P2286. This does not add any top-level range format specifiers (pad/align/width/empty/delimiter), but does add the placeholder colon for them for the future.