我有这段代码:
#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 &&)'
主要问题是在decltype()
表达式上使用f2(rr)
。请注意,f2
的参数为T&&
。这被Scott Meyers称为通用参考:universal reference。我期望f2(rr)
产生一个类型是函数引用的表达式。在GCC中,它正常运行并返回true,因此确认f2(rr)
是函数引用。
当univeral引用与函数名一起使用时,这只是VC ++ 2015的一个错误而不是未定义的行为吗?
编辑:这在VC ++ 2015中正常工作:
int main()
{
cout << f2(rr)(10) <<endl;
}
结果:
400
答案 0 :(得分:2)
通用引用是特殊上下文,其中模板参数可以推导为引用类型。假设我们有
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从函数调用中减去模板参数[temp.deduct.call]
3 [...]如果
P
是对cv-nonqualified模板参数的右值引用,并且参数是左值,则类型&#34;左值引用A
&#34 ;用于代替A
进行类型扣除。 [...]
问题是,在致电f(g)
时,g
是左值?
问这个问题是否有意义?如果T
是函数类型,则T &
和T &&
都可以用于创建对命名函数的引用,而不需要std::move
。函数不存在左值/右值区别。
任意地,C ++标准说是的,g
是左值。函数类型的表达式永远不是rvalues(无论是xvalues还是prvalues)。可以生成对函数类型进行右值引用的类型,但即使这样,它们形成的表达式也是左值。标准中的其他地方有更明确的陈述,但它们来自:
3.10 Lvalues和rvalues [basic.lval]
(1.1) - 左值 [...]指定一个函数或一个对象。 [...]
(1.2) - xvalue [...]也指对象,[...]
(1.4) - rvalue [...]是xvalue,临时对象(12.2)或其子对象,或者与对象无关的值。
(注意:g
不是&#34;值&#34;要么最后一部分不适用。&#34;值&#34;在[basic.types中定义] p4并适用于平凡的可复制类型,其功能类型不是。)
由于g
是左值,T
应推断为int(&)(int)
,这是VC ++中的一个错误。虽然相当微妙。