3

From what I understand one can write template specializations for function template in the std namespace. I have written a CircularBuffer<T> class and implemented a random access iterator for this class. As is the std::copy() algorithm works with my custom iterators but it is not optimal. It iterates through the range and copies elements one by one. I could write a more optimal implementation for trivially copiable types by using std::memcpy() on internal pointers.

My question is that even possible? I know how I would create an overload of std::copy() as a template with output iterator being the template parameter. But that cannot be done since you can only write template specializations of function templates in the std namespace. Any help in pointing me in the right direction would be helpful. From what I could gather through Google, this can't be done, but I would love to be proven wrong :)

rozina
  • 4,120
  • 27
  • 49
  • It seems that `CircularBuffer` is template, and we cannot partial specialize function, so the only solution is overload... But you cannot add it in namespace `std`. – Jarod42 Nov 15 '18 at 12:25
  • 2
    I wouldn't write any function [specializations in new code](https://stackoverflow.com/questions/52760580/will-specialization-of-function-templates-in-std-for-program-defined-types-no-lo). – StoryTeller - Unslander Monica Nov 15 '18 at 12:25
  • @StoryTeller it also states that it is fine as long as there are at least one program defined type involved. – darune Nov 15 '18 at 12:31
  • 1
    @darune - It also says C++20 removed the allowance for function templates, making it okay only for **class templates**. – StoryTeller - Unslander Monica Nov 15 '18 at 12:32
  • True, i somehow missed that. – darune Nov 15 '18 at 12:36
  • 1
    Just to clarify: your `CircularBuffer::iterator` is RandomAccessIterator but not ContiguousIterator, but there are contiguous sections, similar to `std::deque`? – Caleth Nov 15 '18 at 12:56
  • @Caleth a `deque` doesn't provide/satisfy ContiguousIterator, but `vector` do – darune Nov 15 '18 at 13:00
  • @Caleth Yes. `CircularBuffer` has an internal `std::vector` but the beginning of the circular buffer can be after the end in terms of `std::vector` positions. – rozina Nov 15 '18 at 13:05

1 Answers1

1

Maybe your question should be: should I do it ?

Users who make use of your class should already be aware of what std::copy is and how it works and inherently the performance implications. So providing a specialization could make matters worse. std::copy guarantees that N assignments are made; according to the standard:

Exactly (last - first) assignments

Also, it is not uncommon that when std::copy is used, it is also used with back_inserters or other manipulators, that will probably not play well with optimization.

However, you could, for instance, choose to provide a direct access to the buffer like in std::vector::data.

My question is that even possible?

One way around this issue that you seem to have is to export this knowledge - in a sense - to the users of your class. Just add an extra level of indirection. So instead of having iterators to the elements directly you will return iterators to the blocks of memory. Then you will be able to have Contiguous iterators.

https://en.cppreference.com/w/cpp/named_req/ContiguousIterator

darune
  • 10,480
  • 2
  • 24
  • 62
  • From what I understand using [std::copy() on std::vector invokes std::memcpy() or std::memmove()](https://en.cppreference.com/w/cpp/algorithm/copy#Notes). Are you saying that is incorrect behavior? – rozina Nov 15 '18 at 13:50
  • @rozina Since for `int`s, `memcpy` is indistinguishable from assignments, the 'as-if rule' allows the compiler to use one instead of another. – HolyBlackCat Nov 15 '18 at 14:08
  • I want to specialize `std::copy` for my `CircularBuffer`. which I have stated in my question as trivially copy-able types. So hopefully that answers your question that I should write my optimization for `std::copy`. – rozina Nov 15 '18 at 14:11
  • @rozina It's based on the iterator properties as I see it. You have something more akin to a `std::deque` than a `std::vector`. So if this is essential to your class - then I guess you are left with exporting this knowledge to the user so that your iterators can become contiguois in type; see https://en.cppreference.com/w/cpp/named_req/ContiguousIterator – darune Nov 16 '18 at 12:12
  • I don't see how my iterators could become ContiguousIterators, because the range that two iterators represent is not contiguous in memory. However I have an algorithm for copying data from `CircularBuffer` that uses a maximum of 2 calls of `std::copy()`, which for integers translates to `std::memcpy()`. I would love if `std::copy()` could somehow use my algorithm instead of its own. But since I am not supposed to overload `std::copy()`, my question is, if that is possible and how. – rozina Nov 16 '18 at 13:24
  • @rozina thats what im suggesting to you - something ala. this for the begin() function; psuedocode: `return a – darune Nov 16 '18 at 13:36
  • @rozina the outer iterator class type you should create yourselves somehow, as it should have some kind of container semantic when copied, etc. like a `vector` – darune Nov 16 '18 at 13:38
  • I don't think I follow you. How would that make `std::copy()` faster? Btw I already have a RandomAccess iterator programmed and it works fine with `std` algorithms. The problem is the algorithms could be optimized with the knowledge of the container (`CricularBuffer`). – rozina Nov 19 '18 at 07:16