diff --git a/include/fmt/core.h b/include/fmt/core.h index e49033a2..76b684fd 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -208,6 +208,9 @@ struct monostate {}; namespace internal { +// A workaround for gcc 4.8 to make void_t work in a SFINAE context. +template struct void_t_impl { using type = void; }; + #if defined(FMT_USE_STRING_VIEW) template using std_string_view = std::basic_string_view; #elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW) @@ -225,6 +228,9 @@ FMT_CONSTEXPR typename std::make_unsigned::type to_unsigned(Int value) { } } // namespace internal +template +using void_t = typename internal::void_t_impl::type; + /** 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 diff --git a/include/fmt/format.h b/include/fmt/format.h index dffb8b3b..d00f5a76 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -216,6 +216,39 @@ inline Dest bit_cast(const Source& source) { template using iterator_t = decltype(std::begin(std::declval())); +// 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 +struct iterator_category : std::false_type {}; + +template struct iterator_category { + using type = std::random_access_iterator_tag; +}; + +template +struct iterator_category> { + using type = typename It::iterator_category; +}; + +// Detect if *any* given type models the OutputIterator concept. +template 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 + static decltype(*(std::declval())) test(std::input_iterator_tag); + template static char& test(std::output_iterator_tag); + template static const char& test(...); + + using type = decltype(test(typename iterator_category::type{})); + + public: + static const bool value = !std::is_const>::value; +}; + // A workaround for std::string not having mutable data() until C++17. template inline Char* get_data(std::basic_string& s) { return &s[0]; @@ -3306,48 +3339,6 @@ inline typename buffer_context::iterator format_to( basic_format_args(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 struct void_ { typedef void type; }; - -template -struct it_category : std::false_type {}; - -template struct it_category { - typedef std::random_access_iterator_tag type; -}; - -template -struct it_category::type> { - typedef typename T::iterator_category type; -}; - -// Detect if *any* given type models the OutputIterator concept. -template 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 - static decltype(*(std::declval())) test(std::input_iterator_tag); - template static char& test(std::output_iterator_tag); - template static const char& test(...); - - typedef decltype(test(typename it_category::type{})) type; - typedef remove_reference_t result; - - public: - static const bool value = !std::is_const::value; -}; -} // namespace internal - template // using format_context_t = basic_format_context; struct format_context_t { diff --git a/include/fmt/prepare.h b/include/fmt/prepare.h index 6183e7bd..f72ae674 100644 --- a/include/fmt/prepare.h +++ b/include/fmt/prepare.h @@ -514,9 +514,8 @@ struct parts_container_concept_check : std::true_type { template struct has_format_part_type : std::false_type {}; template - struct has_format_part_type< - T, typename void_::type> : std::true_type { - }; + struct has_format_part_type> + : std::true_type {}; static_assert(has_format_part_type::value, "PartsContainer doesn't provide format_part_type typedef");