Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::conditional in nested template class

I'm trying to implement a RingBuffer in the style of the STL. This means I'm also implementing an iterator for it that has to work as either const or non-const. This is just the iterator part:

#include <iterator>
#include <type_traits>

template <typename T> class RingBuffer {
public:
    class Iterator;
    // actual RingBuffer implementation here
};    

template <typename T, bool is_const=false> 
class RingBuffer<T>::Iterator {
public:
    typedef std::ptrdiff_t difference_type;
    typedef T value_type;
    typedef typename std::conditional<is_const, const value_type*, value_type*>::type pointer ;
    typedef typename std::conditional<is_const, const value_type&, value_type&>::type reference ;
    typedef std::random_access_iterator_tag iterator_category;

    // a bunch of functions here
    ...
};

GCC 4.8.0 gives errors for every line where I try to access an iterator, saying something like

no type named 'type' in 'struct std::conditional<is_const, const int*, int*>'

Substituting int for the type that RingBuffer<T> has been instantiated with. I don't get it. is_const has a default value. Why doesn't this work? And why doesn't GCC subsitute in false in the error message, like it substituted int for value_type?

The solution is probably obvious but all the googling in the world didn't get me anywhere. Templates are still kind of confusing to me.

like image 271
MadMonkey Avatar asked Mar 19 '23 05:03

MadMonkey


1 Answers

If you want Iterator to also be templated by bool is_const, you have to declare it as such:

template <typename T> class RingBuffer {
public:
    template <bool is_const = false>
    class Iterator;
    // actual RingBuffer implementation here
};    


template <typename T>
template <bool is_const> 
class RingBuffer<T>::Iterator {
public:
    typedef std::ptrdiff_t difference_type;
    typedef T value_type;
    typedef typename std::conditional<is_const, const value_type*, value_type*>::type pointer ;
    typedef typename std::conditional<is_const, const value_type&, value_type&>::type reference ;
    typedef std::random_access_iterator_tag iterator_category;

    // a bunch of functions here
    ...
};

Explanation: Iterator is a member of a class template, but in your original code, Iterator itself was a non-template class. RingBuffer had one template parameter, T; Iterator was a non-template class; there just wasn't anywhere for is_const to appear. It will become clearer if we remove the outer class for a moment:

class Foo;

template <bool b = false>
class Foo
{
  // something
};

I believe it's obvious the above wouldn't work.

like image 73
Angew is no longer proud of SO Avatar answered Apr 01 '23 19:04

Angew is no longer proud of SO