Search code examples
c++templatesoverloadingoperator-keywordfriend

C++ template how to overloading operator and accessing private property


I am currently trying to implement a simple template-based linked list that takes a generic key/value-pair in C++11. Elements should be added to the list by the += operator. The code looks like this:

list

// Forward declarations
template<typename K, typename V>
class list;

template<typename K, typename V>
list<K, V> &operator+=(list<K, V> &list, const std::tuple<K, V> ele) {
    if (!list.head) {
        // list is empty
        list.head = new element(ele, nullptr);
    }

    return list;
};

// Class definition
template<typename K, typename V>
class list {
private:
    struct element {
        const K key;
        const V value;
        element *next;

        element(const std::tuple<K, V> tuple, element *ele) :
                key(std::get<0>(tuple)),
                value(std::get<1>(tuple)),
                next(ele) { }
    };

    element *head = nullptr;

public:
    friend list<K, V> &operator+=<>(list<K, V> &list, const std::tuple<K, V> ele);
};

I can't get this to compile. Do I have to put the implementation of the operator into the forward declaration or into the class itself? If I put it in the forward-declaration, like in the snippet, I can't seem to use "list.head = new element(ele, nullptr);". Error: expected type-specifier before ‘element’

If I put it into the class itself, I can't access list.head even tho it's a friend.


Solution

  • You should just leave the declaration of the function template before the class template definition (after the forward declaration), to tell the compiler that operator+= specified in the friend declaration is a template. Then define it later. e.g.

    // Forward declarations
    template<typename K, typename V>
    class list;
    
    // declaration of function template
    template<typename K, typename V>
    list<K, V> &operator+=(list<K, V> &l, const std::tuple<K, V> ele);
    
    // Class definition
    template<typename K, typename V>
    class list {
        ...
        friend list<K, V> &operator+=<>(list<K, V> &l, const std::tuple<K, V> ele);
    };
    
    // definition of function template
    template<typename K, typename V>
    list<K, V> &operator+=(list<K, V> &l, const std::tuple<K, V> ele) {
        if (!l.head) {
            // list is empty
            l.head = new typename list<K, V>::element(ele, nullptr);
        }
    
        return l;
    }
    

    PS:

    1. Don't name the parameter with the name list, which conflicts with the name of class template list.

    2. element is a nested struct, in operator+= you should specify it like typename list<K, V>::element.

    3. Using name list (same as std::list) is not a good idea.

    LIVE