diff --git a/include/fmt/base.h b/include/fmt/base.h index 23fb3124..81d8fc03 100644 --- a/include/fmt/base.h +++ b/include/fmt/base.h @@ -2032,6 +2032,17 @@ struct has_back_insert_iterator_container_append< .append(std::declval(), std::declval()))>> : std::true_type {}; +template +struct has_back_insert_iterator_container_insert_at_end : std::false_type {}; + +template +struct has_back_insert_iterator_container_insert_at_end< + OutputIt, InputIt, + void_t()) + .insert(get_container(std::declval()).end(), + std::declval(), + std::declval()))>> : std::true_type {}; + // An optimized version of std::copy with the output value type (T). template ::value&& @@ -2046,6 +2057,8 @@ FMT_CONSTEXPR20 auto copy(InputIt begin, InputIt end, OutputIt out) template ::value && !has_back_insert_iterator_container_append< + OutputIt, InputIt>::value && + has_back_insert_iterator_container_insert_at_end< OutputIt, InputIt>::value)> FMT_CONSTEXPR20 auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt { @@ -2055,7 +2068,11 @@ FMT_CONSTEXPR20 auto copy(InputIt begin, InputIt end, OutputIt out) } template ::value)> + FMT_ENABLE_IF(!(is_back_insert_iterator::value && + (has_back_insert_iterator_container_append< + OutputIt, InputIt>::value || + has_back_insert_iterator_container_insert_at_end< + OutputIt, InputIt>::value)))> FMT_CONSTEXPR auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt { while (begin != end) *out++ = static_cast(*begin++); return out; diff --git a/test/base-test.cc b/test/base-test.cc index f2e46779..1de6a8eb 100644 --- a/test/base-test.cc +++ b/test/base-test.cc @@ -279,6 +279,17 @@ TEST(base_test, is_back_insert_iterator) { std::front_insert_iterator>::value); } +struct minimal_container { + using value_type = char; + void push_back(char) {} +}; + +TEST(base_test, copy) { + minimal_container c; + static constexpr char str[] = "a"; + fmt::detail::copy(str, str + 1, std::back_inserter(c)); +} + TEST(base_test, get_buffer) { mock_buffer buffer; void* buffer_ptr = &buffer;