如果lambdas包含多个语句,那么不允许它推导返回类型有什么原因吗

Is there a reason on not allowing lambdas to deduce the return type if it contains more than one statement?

本文关键字:返回类型 什么 不允许 包含多 lambdas 语句 如果      更新时间:2023-10-16

取自C++0x FDIS(n3290):

如果lambda表达式不包括lambda声明符,则该lambda声明器就好像是()。如果lambda表达式不包括尾部返回类型,则尾部返回类型表示以下类型:

  • 如果复合语句的形式为
    {属性说明符seqopt返回表达式;}
    左值到右值转换(4.1)、数组到指针转换后返回的表达式的类型(4.2)和函数-指针转换(4.3)
  • 否则无效

为什么标准不允许编译器根据第一个找到的return语句来分析复合语句并确定返回类型?

我看不出有什么理由不允许这样做,但也许我忽略了什么。

示例:

int main(){
  // compiler: nope.jpg
  auto l = []{
    // one computation
    // another computation
    // yet another one!
    return something;
  }
}

编辑:请不要回答"因为标准这么说"。:)

这没有技术原因。IIRC它已经由GCC C++维护人员实现了,他说实现起来很简单。

委员会在接受标准中的特征方面非常保守,所以他们采用了这种简单的推导形式,希望以后能接受一种更强大的形式。请参阅美国30号评论中拒绝的原因。

DR 975已经标记为"准备就绪",因此很有可能被接受。

Why doesn't the standard allow the compiler to analyse the compound-statement and determine the return type based on the first found return statement?

在我看来,原因是继承void*的隐式类型转换0int的类型转换,这使得编译器实现者很难从第一个return语句推导类型。参见以下示例:

// "B" is a derived by "D"
int main(){
  auto l = []{
    return (D*)(...);  // should it be "D*" (derived)
    // computation
    return (B*)(...);  // no it should be "B*" (base)
  }
}

第二,

int main(){
  auto l = []{
    return (int*)(...);  // should it be "int*"
    // computation
    return (void*)(...);  // no it has to be "void*"
  }
}

第三,

int main(){
  auto l = []{
    return 0;  // should it be "int"
    // computation
    return (double)(...); // no it has to be "double"
  }
}

此外,当发现两个不相关的return时,还有一个原因与发出编译错误消息有关:

int main(){
  auto l = []{
    return TYPE1;
    // computation
    return TYPE2;
  }
}

现在,问题来了,什么有用的编译器消息应该打印给用户?错误消息必须仅针对其中一个return语句。选择哪个return

我认为这不是一个限制,而是一个允许在身体只有return expression时省略-> decltype(expression)。很明显,在这种情况下返回的类型是什么。

你的建议需要编译器做更多的工作,也需要我们程序员做更多的规则。它能给我们买很多东西吗?

我想是因为这种代码:

void foo( bool k )
{
    auto call= [](){ if( k ) return 42; else return 'c'; };  // what is the return type?
    call();
}

这里的返回类型可以是int或char。由于这些类型中的每一种都可以隐含地转换为另一种,因此编译器无法猜测返回类型是什么。因此,为了避免混淆或避免编译器实现决定它应该是什么类型,调试人员只需告知这将产生一个错误(诊断),允许程序员指定需要什么类型。

因此,这只是为了确保编译器不会编译过于模糊的代码,从而不允许猜测返回类型。