Syntactic restriction in function vs. function template when passing an address

Let’s assume we want to print out the attribute of an arbitrary class through two different functions: One function takes a parameter const Widget&, the other one is a function template that takes a parameter of type const T&. We pass one argument of type Widget and Widget& respectively. The code can look like the following:

#include <iostream>
#include <vector>

class Widget {
public:
    friend std::ostream &operator<<( std::ostream &output, const Widget &w ) { 
        output << "Attr : " << w.attr;
        return output;            
    }
private:
    int attr = 5;
};

void f(const Widget& param) {
  std::cout << param << std::endl;
}

template<typename T>
void f2(const T& param) {
  std::cout << param << std::endl;
}

int main() {
    std::vector<Widget> arg = {Widget()};
    if (!arg.empty()) {
        f(arg[0]);
        //f(&arg[0]);   <-- This leads to a compile time error. Why?
        f2(arg[0]);
        f2(&arg[0]); // <-- In contrast, why does this work if the above fails?
    }
}

Why can we pass an address as argument in the function template, but not in the function? What is T in both valid cases?

Output:

Attr : 5
Attr : 5
0x55feee619eb0

Thanks in advance for the help!

>Solution :

A pointer is not a reference. A reference is not a pointer. arg[0] evaluates to a reference to an object. &arg[0] evaluates to a pointer to the object. That’s what the unary & operator does: it produces a pointer to some object.

The function takes a reference to an object as its parameter, and not a pointer. That’s the reason for the compilation error.

As far as the template is concerned, the template parameter gets deduced to be a pointer to an object, and the instantiated template’s parameter is a reference to a pointer. The instantiated template’s parameter is a Widget * const &, a reference to a const pointer to a Widget.

Leave a Reply