user2807083
user2807083

Reputation: 2982

Can't use CRTP for inner class

I'm trying to use CRTP for common functionality of several iterators types. As stated here Using inner class with CRTP it's impossible to use CRTP for inner class, so I move the base iterator class out of the container class and inherit it inside the container for the iterator. But I still got

error: invalid use of incomplete type 'class ConcreteIteratorBase<Node<int>, std::iterator_traits<Node<int>*>, std::iterator<std::forward_iterator_tag, Node<int>, long int, Node<int>*, Node<int>&> >'

error.

Here is the minimal reproducible example:

#include <algorithm>
#include <functional>
#include <iostream>
#include <iterator>
#include <type_traits>
#include <utility>

template <typename T>
class NotEqFromEqMixin : public T
{
public:
  bool operator!=(T const & other) const
  {
    return !(static_cast<T const &>(*this) == other);
  }
};

template <typename Iterator, typename Traits, typename StdBase>
class IteratorHelperMixin : public NotEqFromEqMixin<Iterator>, public StdBase
{
public:
  using pointer = typename Traits::pointer;
  using reference = typename Traits::reference;

  pointer operator->()
  {
    return &**this;
  }
};

template <typename NodeT, typename TraitsT, typename StdBaseT>
class ConcreteIteratorBase
  : public IteratorHelperMixin<ConcreteIteratorBase<NodeT, TraitsT, StdBaseT>, TraitsT, StdBaseT>
{
public:
  using Super = IteratorHelperMixin<ConcreteIteratorBase<NodeT, TraitsT, StdBaseT>, TraitsT, StdBaseT>;
  using typename Super::pointer;
  using typename Super::reference;

  ConcreteIteratorBase(pointer node) : node(node) {}

  reference operator*() noexcept { return *node; }

  bool operator==(ConcreteIteratorBase const & other) const noexcept { return node == other.node; }

protected:
  pointer node;
};

template <typename Value>
class Node
{
public:
    ~Node() { delete next; }


    Node* next = nullptr;
    Value value;
};

template <typename Value>
class List
{
public:
    using NodeType = Node<Value>;

    void push(Value value)
    {
        NodeType* newNode = new NodeType();
        newNode->value = value;
        newNode->next = head;
        head = newNode;
    }

    class iterator :
        public ConcreteIteratorBase<
            Node<Value>,
            std::iterator_traits<Node<Value>*>,
            std::iterator<std::forward_iterator_tag, Node<Value>>
        >
    {
        using Super = ConcreteIteratorBase<
            Node<Value>,
            std::iterator_traits<Node<Value>*>,
            std::iterator<std::forward_iterator_tag, Node<Value>>
        >;
        
        public:
        iterator(NodeType* ptr = nullptr) : Super(ptr){}

        iterator& operator++()
        {
            if (this->node)
            {
                this->node = this->node->next;
            }
            return *this;
        }

        Value& operator*()
        {
            return this->node->value;
        }

        bool operator==(const iterator& other) const
        {
            return this->node == other.node;
        }
    };

    iterator begin()
    {
        return iterator{head};
    }

    iterator end()
    {
        return iterator{};
    }

    NodeType* head = nullptr;
};


int main(int , char**)
{
    List<int> list;
    for (int i = 0; i < 10; ++i)
    {
        list.push(i);
    }

    for(auto & val : list)
    {
        std::cout << val << " ";
    }
    std::cout << std::endl;
    return 0;
}

Upvotes: 0

Views: 99

Answers (1)

Jarod42
Jarod42

Reputation: 218288

Your issue is that you misuse CRTP as you do a circular inheritance:

ConcreteIteratorBase
-> IteratorHelperMixin<ConcreteIteratorBase, ..> -> NotEqFromEqMixin<ConcreteIteratorBase>
-> ConcreteIteratorBase

You should drop the inheritance here

template <typename T>
class NotEqFromEqMixin //: public T
//                     ^^^^^^^^^^^^
{
public:
  bool operator!=(T const & other) const
  {
    return !(static_cast<T const &>(*this) == other);
  }
};

Demo

Upvotes: 5

Related Questions