mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-31 19:24:48 +02:00
Clean up is_output_iterator
This commit is contained in:
@@ -208,6 +208,9 @@ struct monostate {};
|
|||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
|
// A workaround for gcc 4.8 to make void_t work in a SFINAE context.
|
||||||
|
template <typename... Ts> struct void_t_impl { using type = void; };
|
||||||
|
|
||||||
#if defined(FMT_USE_STRING_VIEW)
|
#if defined(FMT_USE_STRING_VIEW)
|
||||||
template <typename Char> using std_string_view = std::basic_string_view<Char>;
|
template <typename Char> using std_string_view = std::basic_string_view<Char>;
|
||||||
#elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW)
|
#elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW)
|
||||||
@@ -225,6 +228,9 @@ FMT_CONSTEXPR typename std::make_unsigned<Int>::type to_unsigned(Int value) {
|
|||||||
}
|
}
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
|
template <typename... Ts>
|
||||||
|
using void_t = typename internal::void_t_impl<Ts...>::type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
An implementation of ``std::basic_string_view`` for pre-C++17. It provides a
|
An implementation of ``std::basic_string_view`` for pre-C++17. It provides a
|
||||||
subset of the API. ``fmt::basic_string_view`` is used for format strings even
|
subset of the API. ``fmt::basic_string_view`` is used for format strings even
|
||||||
|
@@ -216,6 +216,39 @@ inline Dest bit_cast(const Source& source) {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
using iterator_t = decltype(std::begin(std::declval<T&>()));
|
using iterator_t = decltype(std::begin(std::declval<T&>()));
|
||||||
|
|
||||||
|
// Detect the iterator category of *any* given type in a SFINAE-friendly way.
|
||||||
|
// Unfortunately, older implementations of std::iterator_traits are not safe
|
||||||
|
// for use in a SFINAE-context.
|
||||||
|
template <typename It, typename Enable = void>
|
||||||
|
struct iterator_category : std::false_type {};
|
||||||
|
|
||||||
|
template <typename T> struct iterator_category<T*> {
|
||||||
|
using type = std::random_access_iterator_tag;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename It>
|
||||||
|
struct iterator_category<It, void_t<typename It::iterator_category>> {
|
||||||
|
using type = typename It::iterator_category;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Detect if *any* given type models the OutputIterator concept.
|
||||||
|
template <typename It> class is_output_iterator {
|
||||||
|
// Check for mutability because all iterator categories derived from
|
||||||
|
// std::input_iterator_tag *may* also meet the requirements of an
|
||||||
|
// OutputIterator, thereby falling into the category of 'mutable iterators'
|
||||||
|
// [iterator.requirements.general] clause 4. The compiler reveals this
|
||||||
|
// property only at the point of *actually dereferencing* the iterator!
|
||||||
|
template <typename U>
|
||||||
|
static decltype(*(std::declval<U>())) test(std::input_iterator_tag);
|
||||||
|
template <typename U> static char& test(std::output_iterator_tag);
|
||||||
|
template <typename U> static const char& test(...);
|
||||||
|
|
||||||
|
using type = decltype(test<It>(typename iterator_category<It>::type{}));
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const bool value = !std::is_const<remove_reference_t<type>>::value;
|
||||||
|
};
|
||||||
|
|
||||||
// A workaround for std::string not having mutable data() until C++17.
|
// A workaround for std::string not having mutable data() until C++17.
|
||||||
template <typename Char> inline Char* get_data(std::basic_string<Char>& s) {
|
template <typename Char> inline Char* get_data(std::basic_string<Char>& s) {
|
||||||
return &s[0];
|
return &s[0];
|
||||||
@@ -3306,48 +3339,6 @@ inline typename buffer_context<Char>::iterator format_to(
|
|||||||
basic_format_args<context>(as));
|
basic_format_args<context>(as));
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace internal {
|
|
||||||
|
|
||||||
// Detect the iterator category of *any* given type in a SFINAE-friendly way.
|
|
||||||
// Unfortunately, older implementations of std::iterator_traits are not safe
|
|
||||||
// for use in a SFINAE-context.
|
|
||||||
|
|
||||||
// the gist of C++17's void_t magic
|
|
||||||
template <typename... Ts> struct void_ { typedef void type; };
|
|
||||||
|
|
||||||
template <typename T, typename Enable = void>
|
|
||||||
struct it_category : std::false_type {};
|
|
||||||
|
|
||||||
template <typename T> struct it_category<T*> {
|
|
||||||
typedef std::random_access_iterator_tag type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct it_category<T, typename void_<typename T::iterator_category>::type> {
|
|
||||||
typedef typename T::iterator_category type;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Detect if *any* given type models the OutputIterator concept.
|
|
||||||
template <typename It> class is_output_iterator {
|
|
||||||
// Check for mutability because all iterator categories derived from
|
|
||||||
// std::input_iterator_tag *may* also meet the requirements of an
|
|
||||||
// OutputIterator, thereby falling into the category of 'mutable iterators'
|
|
||||||
// [iterator.requirements.general] clause 4.
|
|
||||||
// The compiler reveals this property only at the point of *actually
|
|
||||||
// dereferencing* the iterator!
|
|
||||||
template <typename U>
|
|
||||||
static decltype(*(std::declval<U>())) test(std::input_iterator_tag);
|
|
||||||
template <typename U> static char& test(std::output_iterator_tag);
|
|
||||||
template <typename U> static const char& test(...);
|
|
||||||
|
|
||||||
typedef decltype(test<It>(typename it_category<It>::type{})) type;
|
|
||||||
typedef remove_reference_t<type> result;
|
|
||||||
|
|
||||||
public:
|
|
||||||
static const bool value = !std::is_const<result>::value;
|
|
||||||
};
|
|
||||||
} // namespace internal
|
|
||||||
|
|
||||||
template <typename OutputIt, typename Char = char>
|
template <typename OutputIt, typename Char = char>
|
||||||
// using format_context_t = basic_format_context<OutputIt, Char>;
|
// using format_context_t = basic_format_context<OutputIt, Char>;
|
||||||
struct format_context_t {
|
struct format_context_t {
|
||||||
|
@@ -514,9 +514,8 @@ struct parts_container_concept_check : std::true_type {
|
|||||||
template <typename T, typename = void>
|
template <typename T, typename = void>
|
||||||
struct has_format_part_type : std::false_type {};
|
struct has_format_part_type : std::false_type {};
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct has_format_part_type<
|
struct has_format_part_type<T, void_t<typename T::format_part_type>>
|
||||||
T, typename void_<typename T::format_part_type>::type> : std::true_type {
|
: std::true_type {};
|
||||||
};
|
|
||||||
|
|
||||||
static_assert(has_format_part_type<PartsContainer>::value,
|
static_assert(has_format_part_type<PartsContainer>::value,
|
||||||
"PartsContainer doesn't provide format_part_type typedef");
|
"PartsContainer doesn't provide format_part_type typedef");
|
||||||
|
Reference in New Issue
Block a user