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?
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.