Griffin
Griffin

Reputation: 21

Understanding the & operator in templates

so im currently reading sams Teach yourself C++ and am unable to figure out when and why the & operator is used, as it seems like it would be uneccesary in many cases like so:

template <typename objectType>   
objectType & GetMax (const objectType & value1, const objectType & value2)    
{
    if (value1 > value2)  
        return value1;    
    else  
        return value2;
};

Another example:

Template <typename T>  
class myTemplateClass  
{  
public:   
    void SetVariable (T& newValue) {m_Value = newValue; };

    T& GetValue() {return m_Value;};

private:   
    T m_Value;  
};

Please help me understand why &, which I know gets the address of the data type, is here! its definately not making learning the STL any easier.......... THANKS! =)

Upvotes: 2

Views: 120

Answers (1)

Ben Voigt
Ben Voigt

Reputation: 283624

That's not an operator, and it's not (directly) related to templates.

It's a type modifier, creating (or indicating or denoting or forming) a reference, just like * creates a pointer.

Much of the time, it's an optimization rather than a necessity. Two Three cases where it is necessary:

  • In the copy-constructor, it's needed to avoid infinite recursion:

    class X
    {
         //X(X);
         // pass by value, the formal parameter is a copy of the actual parameter
         // the copy constructor must be called to make the copy
    
         X(const X&); // pass by reference, ok, no copy constructor call necessary
    };
    

    Const references in general save having to copy a large object, which is a useful optimization with no surprising behavior.

  • When the return type of a function, especially operator[] overload, must appear on the left hand side of an expression:

    class Container
    {
         //Element operator[](int index);
         // problematic because c[i] is a temporary
         // so c[i] = 5; doesn't actually modify the collection, like it would with an array
    
         Element& operator[](int index); // correct
    

    };

    As a similar case, for operators that mutate their left operand, like compound assignment and stream insertion, it's necessary to use a non-const reference parameter.

Any other cases (e.g. output arguments) can (and I think should) be handled with pointers, since a function call that LOOKS like pass-by-value but changes its argument violates the principle of least-surprise. Perfect example: auto_ptr<int> a = new int(5); f(a); /* is a still valid !?! */

Which brings us to case 3, (created because somebody used non-const references outside of operators):

  • In templates, when the actual type might by auto_ptr or unique_ptr, a reference is needed to avoid inferring a type that destroys the original:

    auto_ptr<int> a = new int(5);
    
    //template<typename T>
    //void dump_target( T handle ) { cout << *item; }
    // bad: dump_target(a); destroys *a
    
    template<typename T>
    void dump_target( const T& handle ) { cout << *item; } // correct
    

Upvotes: 8

Related Questions