在临时之前调用的析构函数应该超出范围

时间:2015-02-10 19:39:51

标签: c++ auto c++14 decltype visual-studio-2015

我有一些代码在VS2015下失败,但在GCC下工作。我很确定这个bug是Visual Studio的,但我想确保我对decltype(auto)的理解是正确的。

#include <iostream>
using namespace std;

string zero_params()
{
  return "zero_params called.";
}

template< typename F >
auto test1( F f ) -> decltype(auto)
{
  return f();
}

int main() {
  cout << std::is_rvalue_reference< decltype(test1(zero_params)) >::value << endl;
  cout << test1(zero_params) << endl;

  cout << "Done!" << endl;
  return 0;
}

在Visual Studio下,zero_params返回的字符串被推导为右值引用。此外,该对象的析构函数在test1()中被调用,其中调用f的返回发生(这似乎是破坏&amp;&amp;对象的合理位置)。

在GCC下,返回的字符串不会被推断为右值引用。正如我所期望的那样,在cout语句中使用后调用析构函数。

在Visual Studio下将返回类型指定为'string'而不是decltype(auto)可以修复它,就像在test1中返回f()时使用remove_reference_t一样。

我的期望是GCC是正确的,因为zero_params()的函数签名是字符串,而不是字符串&amp;&amp;所以如果它使用decltype(auto),我会期望不引用'冒泡'到test1的返回类型。

这是正确的评估吗?


LATE EDIT:

我发现用VS2015解决这个问题的另一种方法是在lambda中包含给test1的函数:

cout << test1(zero_params) << endl;

为:

cout << test1( [](auto&&... ps) { return zero_params(std::forward<decltype(ps)>(ps)...); } ) << endl;

1 个答案:

答案 0 :(得分:2)

所以based on the comments我们可以得出结论:

错误是:

  • 编译器应该将返回类型推断为字符串
  • 它实际上推断它是字符串&amp;&amp;
  • 因此它过早地破坏了价值

解决方法是:

  • 不要将decltype(auto)用于函数的返回类型
  • 在将函数传递到
  • 之前将函数包装在lambda表达式中