VC++ Decltype 和通用引用或未定义行为的错误?

VC++ Bug with Decltype and Universal Reference or Undefined Behavior?

我有这个代码:

#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;
}

当使用 VC++2015 编译时,我得到了这个错误:

error C2893: Failed to specialize function template 'T f2(T &&)'

主要问题是在表达式 f2(rr) 上使用 decltype()。注意f2的参数是T&&。这被 Scott Meyers 称为 Universal Referenceuniversal reference。我期待 f2(rr) 产生一个类型为函数引用的表达式。在 GCC 中,它正常运行并且 returns 为真,因此确认 f2(rr) 是一个函数引用。

这只是 VC++2015 的错误,而不是当通用引用与函数名称一起使用时的未定义行为吗?

编辑:这在 VC++2015 中正常工作:

int main()
{
  cout << f2(rr)(10) <<endl;
}

结果:

400

通用引用是可以将模板参数推导为引用类型的特殊上下文。假设我们有

template <typename T> auto f(T &&) -> T;
int i;
int g(int);

f(i)T 推导为 int & 以形成 auto f<int &>(int &) -> int &.
f(std::move(i))T 推导为 int 以形成 auto f<int>(int &&) -> int.

发生这种情况的规则如下:

14.8.2.1 Deducing template arguments from a function call [temp.deduct.call]

3 [...] If P is an rvalue reference to a cv-unqualified template parameter and the argument is an lvalue, the type "lvalue reference to A" is used in place of A for type deduction. [...]

问题是,调用f(g)时,g是左值吗?

问这个问题有意义吗?如果 T 是一个函数类型,那么 T &T && 都可以用来创建对命名函数的引用,而不需要 std::move。函数不存在 lvalue/rvalue 区别。

任意地,C++ 标准说是的,g 是一个左值。函数类型的表达式永远不是右值(无论是 xvalues 还是 prvalues)。可以生成函数类型的右值引用类型,但即便如此,由它们形成的表达式也是左值。标准中其他地方有更明确的陈述,但它们来自:

3.10 Lvalues and rvalues [basic.lval]

(1.1) -- An lvalue [...] designates a function or an object. [...]

(1.2) -- An xvalue [...] also refers to an object, [...]

(1.4) -- An rvalue [...] is an xvalue, a temporary object (12.2) or subobject thereof, or a value that is not associated with an object.

(注意:g 也不是“值”,因此最后一部分不适用。“值”在 [basic.types]p4 中定义并适用于平凡可复制的类型,哪些函数类型不是。)

因为g是一个左值,T应该推导为int(&)(int),这是VC++中的一个错误。虽然很微妙。