在C++ 11中省略返回类型

Cli*_*ton 41 c++ return-value c++11

我最近发现自己在C++ 11模式下使用gcc 4.5的以下宏:

#define RETURN(x) -> decltype(x) { return x; }
Run Code Online (Sandbox Code Playgroud)

并编写如下函数:

template <class T>
auto f(T&& x) RETURN (( g(h(std::forward<T>(x))) ))
Run Code Online (Sandbox Code Playgroud)

我一直这样做是为了避免不得不有效地编写函数体两次,并保持身体和返回类型的同步(这在我看来是等待发生的灾难)的不便.

问题是这种技术只适用于一行功能.所以当我有这样的事情时(复杂的例子):

template <class T>
auto f(T&& x) -> ...
{
   auto y1 = f(x);
   auto y2 = h(y1, g1(x));
   auto y3 = h(y1, g2(x));
   if (y1) { ++y3; }
   return h2(y2, y3);
}
Run Code Online (Sandbox Code Playgroud)

然后我必须在返回类型中添加一些可怕的东西.

此外,每当我更新函数时,我都需要更改返回类型,如果我没有正确更改它,如果我很幸运,我会收到编译错误,或者更坏的情况下会出现运行时错误.必须将更改复制并粘贴到两个位置并保持同步,我觉得这不是一个好习惯.

而且我想不出一种情况,我希望在返回时使用隐式强制转换而不是显式强制转换.

当然有一种方法可以要求编译器推断出这些信息.编译器保守秘密有什么意义?我认为C++ 11的设计不需要这样的复制.

ems*_*msr 23

似乎g ++ 4.8正在实现自动返回类型推导.这个补丁由杰森·梅里尔(Jason Merrill)投入,他也在发送C++的论文 - 1Y用于该功能.该功能可用-std = c ++ 1y.

还在玩它.

  • 返回类型推导已经投票到C++ 14.[最新论文](http://isocpp.org/files/papers/N3638.html)有详细信息. (7认同)

Mar*_*wis 11

这种行为的基本原理在草案8.3.5p12中给出:

对于在declarator-id之前指定更复杂的类型,trailing-return-type最有用:

template <class T, class U> auto add(T t, U u) -> decltype(t + u);
Run Code Online (Sandbox Code Playgroud)

而不是

template <class T, class U> decltype((*(T*)0) + (*(U*)0)) add(T t, U u);
Run Code Online (Sandbox Code Playgroud)

所以这实际上只是为了简化引用参数名称有帮助的情况.

如果你假设C++ 能从函数体中推断函数的返回类型:这不会飞.C++(和C)的目标是通过将声明与实现分离来实现模块化,因此在调用时,您可能没有可用的函数体.但是,每个调用者都需要知道所调用的每个函数/方法的参数类型和返回类型.


Gra*_*vis 7

如果您只是尝试设置返回类型,请将其设置为模板参数.这样,您可以更改与返回类型相关的所有内容,而无需实际更改功能.如果您希望在此示例中使用,则可以设置默认返回类型.

template <class R = int, class T>
R f(T&& x)
{
   ...
   return h2(y2, y3);
}
Run Code Online (Sandbox Code Playgroud)

下面的代码证明了它的有效性.

演示代码:

#include <iostream>
#include <iomanip>

template <class T, class S>
T h2(T& x, S& y)
{
  return x + y;
}

template <class R = int, class T>
R f(T& x)
{
  auto y2 = x;
  auto y3 = x;
  return h2(y2, y3);
}

int main(int argc, char** argv)
{
  int x = 7;
  std::string str = "test! ";

  auto d = f<double>(x);
  auto i = f(x); // use default type (int)
  auto s = f<std::string>(str);

  std::cout << std::fixed << std::setprecision(4);
  std::cout << "double: " << d << std::endl;
  std::cout << "int: " << i << std::endl;
  std::cout << "string: " << s << std::endl;

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

OUTPUT:

double: 14.0000
int: 14
string: test! test!
Run Code Online (Sandbox Code Playgroud)

不幸的是,您正在寻找的确切功能尚未存在,并且不是C++ 0x规范的一部分.但是,在草拟时,这可能是C++ 1x规范的一部分.在那之前,坚持模板.


Ben*_*igt 6

编辑:oops,我刚刚意识到trailing-return-type说明符和return语句之间存在范围差异.特别:

auto f(int a)
{
    char r[sizeof(f(a))+1];
    return r;
}
Run Code Online (Sandbox Code Playgroud)

KABOOM!


上一个答案:

遗憾的是,在这种情况下,语言没有提供编译器推断返回类型的语法,因为显示推理是可能的很简单.

具体来说,我们讨论的是函数中只有一个return语句的情况.

与返回语句的函数位置或前面的代码有多复杂无关,应该清楚以下转换是可能的:

return (ugly expression);
Run Code Online (Sandbox Code Playgroud)

auto return_value = (ugly expression);
return return_value;
Run Code Online (Sandbox Code Playgroud)

如果编译器可以推断出类型return_value(并且根据C++ 0x规则,它可以),那么return_value可以选择推断类型作为函数的返回类型.

因此,在我看来,对C++ 0x进行修改时,只有在返回语句的多重性不是一个时才需要尾随返回类型说明符才是可行的并且可以解决问题.