为什么我们不能自动推导出返回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 + b
和a + c
expression式产生不同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组添加一个编译器扩展。