Есть ли причина, по которой лямбды не могут выводить тип возвращаемого значения, если он содержит более одного оператора? - PullRequest
6 голосов
/ 05 июня 2011

Взято из C ++ 0x FDIS (n3290):

Если лямбда-выражение не включает в себя лямбда-декларатор, это как если бы лямбда-декларатор был ().Если лямбда-выражение не включает в себя тип конечного возврата, это означает, что тип конечного возврата обозначает следующий тип:

  • , если составной оператор имеет форму
    {attribute-specier-seq opt возвращаемое выражение;}
    тип возвращаемого выражения после преобразования lvalue-в-значение (4.1), преобразования массива в указатель (4.2) и преобразования функции в указатель (4.3);
  • в противном случае,void.

Почему стандарт не позволяет компилятору анализировать составной оператор и определять тип возврата на основе первого найденного return оператора?

Я не вижу причин, чтобы не допустить этого, но, возможно, я что-то упускаю.

Пример:

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

Редактировать : Пожалуйста, нет ", потому чтостандарт так говорит "ответы.:)

Ответы [ 4 ]

10 голосов
/ 27 ноября 2011

Технических причин для этого нет.IIRC это уже было реализовано сопровождающим GCC C ++, и он сказал, что это тривиально реализовать.

Комитет очень консервативен в отношении принятия функций в Стандарт, поэтому они пошли с этой простой формой вывода и позже, надеюсь, примут более мощную форму.См. Причину отклонения в комментарии US 30 .

DR 975 уже помечено как "готово", поэтому велики шансы, что оно будет принято.

4 голосов
/ 05 июня 2011

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* и 0 приведение типов к int, что затрудняет для разработчиков компилятора вывод типа первое 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 выбрать?

1 голос
/ 05 июня 2011

Я считаю, что это не ограничение, а допуск , чтобы опустить -> decltype(expression), когда тело просто return expression. Совершенно очевидно, что тип возвращаемого значения в этом случае.

Ваше предложение требует гораздо больше работы для компиляторов и намного больше правил для нас, программистов. Это нас много покупает?

0 голосов
/ 05 июня 2011

Полагаю, это из-за кода такого типа:

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

Здесь тип возвращаемого значения может быть int или char.Поскольку каждый из этих типов неявно конвертируется в другой, компилятор слишком двусмысленно догадывается, что является возвращаемым типом.Поэтому, чтобы избежать путаницы или избежать реализации компилятором решения о типе ведьмы, комитет должен просто сказать, что это должно привести к ошибке (диагностике), позволяющей программисту указать, какой тип требуется.

Так что этопросто чтобы убедиться, что компиляторы не скомпилируют код, который слишком неоднозначен, чтобы можно было угадывать возвращаемый тип.

...