1
template<class T>
class BNode
{
public:
    T data;
    BNode *parent, *left, *right;

    explicit BNode(T d) : data(d), parent(nullptr), left(nullptr),
                          right(nullptr)
    {}

};

Problem 1: This is right.

template<class T>
void BST<T>::InOrder_(BNode<T> *&s)
{
    if (s)
    {
        InOrder_(s->left);
        cout << s->data << ' ';
        InOrder_(s->right);
    }
}

Problem 2: This is wrong.

template<class T>
void BST<T>::InOrder_(const BNode<T> *&s)
{
    if (s)
    {
        InOrder_(s->left);
        cout << s->data << ' ';
        InOrder_(s->right);
    }
}

error: cannot bind non-const lvalue reference of type 'const BNode<int>*&' to an rvalue of type 'const BNode<int>*'

     InOrder_(s->left);
              ~~~^~~~

Problem 3: This is right.

template<class T>
void BST<T>::InOrder_(BNode<T> *const &s)
{
    ......
}

Problem 4: This is right.

template<class T>
void BST<T>::InOrder_(const BNode<T> *const &s)
{
    ......
}

Can you tell me the above problems why is right or wrong? Thank you!

aschepler
  • 70,891
  • 9
  • 107
  • 161
Alan Zhang
  • 13
  • 3
  • When using `const` *before* the type, it takes it as the whole type so when you write `const BNode *` it actually means a pointer of type `const BNode`(**constants of the BNode class**), but when you write `BNode * const` it is a constant variable of class BNode. In other words, a *pointer of constants* is modifiable but not a constant **pointer**. – Ruks Aug 25 '18 at 03:34
  • 1
    I don't see why you're using a reference in any of those cases which just makes the code harder to read and understand. – Retired Ninja Aug 25 '18 at 03:35
  • As already mentioned, a reference is only used when you are trying to change the value of the variable mentioned inside the function call *inside the function*. – Ruks Aug 25 '18 at 03:40

1 Answers1

1
InOrder_(const BNode<T> *&s) {

Accepts a mutable reference to a pointer to const. It means that the function can't change the BNode object, but it can set a new pointer.

void BST<T>::InOrder_(const BNode<T> *&s) 
{
  if (s)
  { 
    InOrder_(s->left);

Here, s->left is a constant pointer (since s points to const BNode), that points to a mutable BNode. The pointer itself can't be modified, but it points to an object that can.

The problem is that InOrder_ can modify the pointer itself (a regular reference to a pointer). The compiler can't allow that, because at the call site the pointer can't be modified (the pointer is const).

To fix this, declare the pointer itself as const, and not only the object it points to:

void BST<T>::InOrder_(const BNode<T> * const &s) 

Read the declaration from right to left: s is a reference to a constant pointer to a constant object of type BNode.

Michael Veksler
  • 8,217
  • 1
  • 20
  • 33