带有Decltype和Universal Reference或Undefined Behavior的VC ++ Bug?

时间:2016-12-26 12:55:27

标签: c++ c++11 decltype compiler-bug

我有这段代码:

#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

1 个答案:

答案 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 ++中的一个错误。虽然相当微妙。