vendredi 20 septembre 2019

C++ templated classes gives `error: non-template X used as template` [duplicate]

This question already has an answer here:

The question is why doesn't this code compile and specifically why do I get some weird compilation errors like

error: non-template ‘C_Iterator’ used as template ?

#include <type_traits>  // fot std::enable_if
#include <iostream>

template <class T>
struct Container{

  template <bool Is_Const>
  struct C_Iterator{

    using value_type        = T;
    using pointer           = T*;
    using reference         = T&;
    using difference_type   = std::ptrdiff_t;
    using iterator_category = std::random_access_iterator_tag;

    T* p;

    // args c-tors
    C_Iterator(T *p_): p(p_) {}
    // Copy
    C_Iterator(const C_Iterator<Is_Const>& other) = default;

    template<bool Was_Const, class = typename std::enable_if<Is_Const || !Was_Const>::type>
    C_Iterator(const C_Iterator<Was_Const>& other) : p{other.p}{}

    C_Iterator &operator=(const C_Iterator &other){
        p = other.p;
        return *this;
    }

    reference operator*() {return *p;}

    // some other stuff here
  };

  using iterator = C_Iterator<false>;
  using const_iterator = C_Iterator<true>;

  Container(T v) { storage = new int[1]; storage[0]=v; }
  ~Container() { delete storage;  }

  inline iterator       begin()       { return iterator(storage);}
  inline const_iterator begin() const { return const_iterator(storage);}

  T* storage;

};


template <class T>
struct Iterable_Wrapper{

  template <bool Is_Const>
  struct W_Iterator{

    using value_type        = T;
    using pointer           = T*;
    using reference         = T&;
    using iterator_category = std::forward_iterator_tag;

    using c_iterator = typename Container<T>::C_Iterator<Is_Const>;

    c_iterator it;

    // args c-tors
    W_Iterator( c_iterator it_ ): it(it_) {}

    // Copy
    W_Iterator(const W_Iterator<Is_Const>& other) = default;

    template<bool Was_Const, class = typename std::enable_if<Is_Const || !Was_Const>::type>
    W_Iterator(const W_Iterator<Was_Const>& other) : it{other.it}{}

    W_Iterator &operator=(const W_Iterator &other){
        it = other.it;
        return *this;
    }

    reference operator*() {return *it;}

    // some other stuff here
  };

  using iterator = W_Iterator<false>;
  using const_iterator = W_Iterator<true>;

  Iterable_Wrapper(T v) : wrapped_container(v) {}
  ~Iterable_Wrapper() {}

  inline iterator       begin()       { return iterator(wrapped_container.begin());}
  inline const_iterator begin() const { return const_iterator(wrapped_container.begin());}

  Container<T> wrapped_container;

};

int main()
{
  Container<int> c{5};
  auto it { c.begin() };
  std::cout << *it << std::endl;

  const Container<int> c2{10};
  auto it2 { c2.begin() };
  std::cout << *it2 << std::endl;


  Iterable_Wrapper<int> w{15};
  auto it3 { w.begin() };
  std::cout << *it3 << std::endl;

  return 0;
}

To give a bit more context, I'm trying to get a re-implementation of a few data structures as an exercise and I'm now struggling at a "composite" data structure ( a HashSet, an over-simplified version of an unordered_set ) implemented as a vector of buckets with a linked_list in each of them. Both vector and list implementation are my own, so it's likely the fault in the implementation is uphill and that's why the minimal example is so long.. I needed to include both "mock" classes.

As I said, the above code cannot compile and if I run g++ file.cpp -std=c++11 gives me

file.cpp:61:57: error: expected ‘;’ before ‘<’ token

i.e. he's expecting using c_iterator = typename Container<T>::C_Iterator<Is_Const>; to be using c_iterator = typename Container<T>::C_Iterator instead.

Weird, and indeed if I run it complains that error: ‘typename Container<int>::C_Iterator’ names ‘template<bool Is_Const> struct Container<int>::C_Iterator’, which is not a type

so the template should be there! What's wrong with my code?

Aucun commentaire:

Enregistrer un commentaire