I found something interesting when I was writing a simple homework.
struct Node
{
string key;
int value;
Node *next;
Node(const string &theKey, int theValue):key(theKey), value(theValue), next(nullptr){}
Node(const string &theKey, int theValue, Node *n):key(theKey), value(theValue), next(n){}
};
typedef Node * ListType;
ListType listFind(const ListType &list, const string &target)
{
if(!list) return NULL;
ListType cur = list;
while(cur)
{
if(cur->key == target)
return cur;
cur = cur->next;
}
return NULL;
}
bool listInsert(ListType &list, const ListType &target)
{
if(!listFind(list, target->key))
{
target->next = list;</span>
list = target;
return true;
}
return false;
}
void listPrint(const ListType &list, ostream &out)
{
ListType cur = list;
while (cur)
{
out << cur->key << ":" << cur->value << ' ';
cur = cur->next;
}
out << endl;
}
int main()
{
Node *A = new Node("Melody", 100);
listInsert(A, new Node("Luo", 99));
listPrint(A, cout);
return 0;
}
Please take care of this sentence:
target->next = list;
Nothing special at first glance. Yet have you noticed the parameter type:
const ListType &target
Yes, it is modified by a 'const'. How are we able to change the content anyway?
Well, the reason is that, 'const ListType &target' is different from 'const Node *&target'. The first one is a 'top-level const', i.e. the pointer itself is const. The latter means that the content pointed by the pointer is const, aka a 'low-level const'.
Typically we are not allowed to pass a rvalue to a non-const parameter, because after all it's allowed and very likely not our desire to change the content of a rvalue. That's why we need a const modifier. Yet a type alias breaks the rule to some extent, for here we are able to change the content anyway. That's the reason why I don't prefer type alias.
One more thing.
int *a = new int(0); const int *b = a; //OK
const int *&c = a; //WRONG, the compiler complains that
on-const lvalue reference to type
'const int *' cannot bind to a value of unrelated type
'int *'