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 Reference:universal 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++中的一个错误。虽然很微妙。
我有这个代码:
#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 Reference:universal 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 toA
" is used in place ofA
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++中的一个错误。虽然很微妙。