Home > Mobile >  How to make an overload for templated functions for a custom container's iterator
How to make an overload for templated functions for a custom container's iterator

Time:04-21

This is a generic question about templating, I am using advance as an example. Assume there are reasons I can't use ADL or hidden friends here.

The definition of std::advance is:

template< class InputIt, class Distance >
constexpr void advance( InputIt& it, Distance n );

For the sake of argument, say I have a container H, with iterators which for some reason I want to overload std::advance for:

template <typename T, class Allocator=std::allocator<T>>
class H
{
  // etc
  class iterator;
};

How does one design an advance overload to match that iterator, and have C correctly select the overload when calling advance on H's iterator class? The code below does not work because only H is specified in the templating, not the iterator itself:

template< template <typename, class> class container, class T, class Allocator, class Distance >
constexpr void advance( container<T, Allocator>::iterator& it, Distance n );

I can't quite work out how to specify the iterator specifically in the template line.

CodePudding user response:

A friend of mine came up with a solution based on tags (empty structs).

Basically, put a unique empty struct in the iterator class then use a few templates to build a C 20 concept out of them, then use that to match in the template overload:

   template <typename T, class A = std::allocator<T>>
   class H
   {
      // etc
   public:
      class iterator
      {
      public:
         struct cheat_tag {};
         // etc
      };
   };

   template <class, class = void>
   struct is_cheating : false_type {};

   template <class T>
   struct is_cheating<T, void_t<typename T::cheat_tag>> : true_type {};

   template <class T>
   concept h_iterator = is_cheating<T>::value;

   namespace std
   {
      template <h_iterator T, class D>
      constexpr void advance(T&, D)
      {
         // etc
      }
   }

Provided you match the signature of the template you're trying to overload exactly, this should work.

  • Related