I have this code:
#include <iostream>
#include <type_traits>
using namespace std;
template<typename T>
T f2(T&&t) {
return t;
}
int rr(int i) {
return 40*i;
}
int main()
{
cout << is_function< remove_reference<decltype(f2(rr))>::type>::value << endl;
}
When compiled with VC++2015, i got this error:
error C2893: Failed to specialize function template 'T f2(T &&)'
The main issue is with using decltype()
on the expression f2(rr)
. Note that f2
's parameter is T&&
. This is called Universal Reference by Scott Meyers: universal reference. I am expecting f2(rr)
yields an expression whose type is a function reference. In GCC, it runs normally and returns true, and hence, confirms that f2(rr)
is a function reference.
Is this simply a bug with VC++2015 rather than undefined behavior when the univeral reference is used with a function name?
EDIT: This works correctly in VC++2015:
int main()
{
cout << f2(rr)(10) <<endl;
}
result:
400
Universal references are the special context where a template parameter can be deduced as a reference type. Suppose we have
f(i)
deducesT
asint &
to formauto f<int &>(int &) -> int &
.f(std::move(i))
deducesT
asint
to formauto f<int>(int &&) -> int
.The rules for when this happens are given as:
The question is, when calling
f(g)
, isg
an lvalue?Does it even make sense to ask the question? If
T
is a function type, thenT &
andT &&
can both be used to create references to named functions, without any need forstd::move
. The lvalue/rvalue distinction doesn't exist for functions.Arbitrarily, the C++ standard says that yes,
g
is an lvalue. Expressions of function type are never rvalues (whether xvalues or prvalues). It's possible to produce types that are rvalue references to function types, but even then, the expressions formed by them are lvalues. There are more explicit statements elsewhere in the standard, but they follow from:(Note:
g
is not a "value" either, so that last part doesn't apply. "Value" is defined in [basic.types]p4 and applies to trivially copyable types, which function types are not.)Since
g
is an lvalue,T
should be deduced asint(&)(int)
, and this is a bug in VC++. Quite a subtle one though.