1

VS 2013 says that it cannot specialize the function template in the following code:

struct W { };

template <class T>
typename T::result_type
f (const W & w, T && t) {
    return 0;
}

/* ... */
struct V { typedef int result_type; };

W w {};
V v {};
f (w, v);

If I replace typename T::result_type by int or if I replace the universal reference T&& by T&, it does not complain.

In my opinion, the above code is correct. Is this a compiler bug, or am I doing anything wrong?

JohnB
  • 13,315
  • 4
  • 38
  • 65

1 Answers1

2

The compiler is right. The way forwarding references(1) work is that if passed an lvalue of type U, they use U& instead of U for type deduction. Since v in your case is an lvalue, T is deduced to V&. V& is a reference type, it doesn't have a nested type (it cannot even have one).

When working with forwarding references, you have to always use std::remove_reference to get at the underlying type:

template <class T>
typename std::remove_reference<T>::type::result_type
f (const W & w, T && t) {
    return 0;
}

(1) Since CppCon 2014, "forwarding reference" was accepted as replacement term for "universal reference," since it captures the intent better.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • Thank you so much! I would never have thought of this myself. I will accept your answer as soon as I can. – JohnB Feb 24 '15 at 10:48