为什么我们不能自动推导出返回types?

最近我正在做一个朋友,他希望把C ++做成更多的Haskell-y,我们想要一个基本如此的函数:

auto sum(auto a, auto b) { return a + b; } 

显然,我不能使用自动作为参数types,所以我改变了这个:

 template<class A, class B> auto sum(A a, B b) { return a + b; } 

但是这也行不通。 我们最终意识到我们需要这个:

 template<class A, class B> auto sum(A a, B b) -> decltype(a + b) { return a + b; } 

所以我的问题是,这有什么意义? 不是decltype只是重复信息,因为编译器可以看看return语句吗?

我认为,也许这是必要的,所以我们可以只包含一个头文件:

 template<class A, class B> auto sum(A a, B b) -> decltype(a + b); 

…但是我们无法使用这样的模板。

另一件我考虑的事情是编译器可能更容易,但似乎实际上会更困难。

情况1:使用decltype

  • 找出decltype语句的types
  • 找出任何返回值的types
  • 看看他们是否匹配

情况2:没有decltype

  • 找出任何返回值的types
  • 看看他们是否匹配

所以考虑到这些,使用decltype的尾随返回types有什么意义?

如果我们有以下情况会怎样?

 template<class A, class B, class C> auto sum(A a, B b, C c) { if (rand () == 0) return a + b; // do something else... return a + c; } 

..其中a + ba + cexpression式产生不同types的结果。 编译器决定把这个函数作为返回types,为什么? 这种情况已经被C ++ 11 lambda覆盖了,只要return语句可以推导为相同的types就可以省略返回types(NB需要标准引用,有些来源声称只允许一个返回expression式,这是一个海湾合作委员会小故障)。


一个技术原因是C ++允许定义和声明是分开的。

 template<class A, class B> auto sum(A a, B b) -> decltype(a + b); template<class A, class B> auto sum(A a, B b) -> decltype(a + b) { } 

模板的定义可以在标题中。 或者它可能在另一个文件中,这样当你浏览一个接口的时候,你就不必通过页面和页面的function定义了。

C ++必须考虑所有的可能性。 将追溯返回types限制为函数定义意味着你不能做这样简单的事情:

 template<class A, class B> class Foo { auto sum(A a, B b) -> decltype(a + b); } template<class A, class B> auto Foo<A, B>::sum(A a, B b) -> decltype(a + b) { } 

但是我们无法使用这样的模板。

首先,尾随返回types不是纯粹的模板事物。 他们为所有function工作。 其次,说谁? 这是完全合法的代码:

 template<class A, class B> auto sum(A a, B b) -> decltype(a + b); template<class A, class B> auto sum(A a, B b) -> decltype(a + b) { } 

模板的定义可以在标题中。 或者它可能在另一个文件中,这样当你浏览一个接口的时候,你就不必通过页面和页面的function定义了。

C ++必须考虑所有的可能性。 将追溯返回types限制为函数定义意味着你不能做这样简单的事情:

 template<class A, class B> class Foo { auto sum(A a, B b) -> decltype(a + b); } template<class A, class B> auto Foo<A, B>::sum(A a, B b) -> decltype(a + b) { } 

这对于很多程序员来说是相当普遍的。 想用这种方式进行编码没有任何问题。

lambdas没有返回types的唯一原因是因为它们必须具有定义的函数体。 如果将追溯返回types限制为只有定义可用的函数,则不能使用上述任一情况。

没有技术上的原因,为什么这是不可能的。 他们没有的主要原因是因为C ++语言移动速度非常慢,需要很长时间才能添加特征。

几乎可以用lambdaexpression你想要的语法(但是你不能在lambdaexpression式中使用模板化的参数,没有任何理由)。

 auto foo = [](int a, double b) { return a + b; }; 

是的,在某些情况下,返回types不能被自动推断出来。 就像在一个lambda中一样,只需要在这些模糊的情况下声明返回types即可。

目前,这些限制是如此武断以至于令人沮丧。 另请参阅删除增加挫折的概念。

在Dave Abrahams的博客文章中 ,他讨论了使用这个函数语法的build议:

 []min(x, y) { return x < y ? x : y } 

这是基于多态lambda的可能build议。 他还开始在这里更新clang来支持这个语法。

尽pipe没有技术上的障碍,但希望说服委员会增加这样的语言function的希望不大。 但也许可以说服GCC组添加一个编译器扩展。