+2  A: 

The problem is caused by reference decay: (correct term is "reference collapse")

template < typename T >
void f(T && t) { .... }

int x; f(x); // what is f()?

The answer to the question in the code is that f() is:

void f(T& && t) { .... }

Which because of reference decay turns into this:

void f(T& t) { .... }

As you can expect, this will of course be ambiguous with anything defined as:

template < typename T >
void f(T & t) { .... }

This might work (fixed version):

#include <type_traits>
#include <utility>

template < typename T >
struct pointer
{
  pointer(T& t) {}
  pointer(T&& t) {}
};

template < typename T >
pointer<typename std::remove_reference<T>::type> 
address_of(T && t)
{ 
  return pointer<typename std::remove_reference<T>::type>(std::forward<T>(t));
}

int main()
{
  int x = 5;
  pointer<int> o = address_of(x);
  pointer<int> p = address_of(5);
}

The reason being that this reference decay stuff only happens in functions that are templated on T. In this case your pointer class is, but the constructors are not actually templates themselves and so T& is never a valid T for the T&& version.

The first version still had the same problem as your code since address_of was just using T as the template parameter for pointer. We actually need the raw type.

Noah Roberts
That makes sense, thanks. Any thoughts on how to achieve the behaviour I *do* want?
Jon Purdy
What is reference decay?
Andres Jaan Tack
@Jon - one. Not positive it will work but I put it in my answer.
Noah Roberts
@Andres - http://thbecker.net/articles/rvalue_references/section_08.html
Noah Roberts
Jon Purdy
Because I forgot to remove the reference in T before using it to instantiate pointer<>. Fixed.
Noah Roberts
That did it! I suspected it would be something involving `remove_reference` but I got pulled away and didn't have a chance to test it. Works like a charm.
Jon Purdy
You might put a static_assert in your pointer class that checks if T is a reference and pukes if so. This would make the compiler error more sensible to others since the error they'll get if they do pass a reference as T is what you got about overloading.
Noah Roberts
Not a bad idea, but unnecessary for my purposes: the code that makes use of this feature is autogenerated and will not be touched by humans.
Jon Purdy