Мне любопытно, каковы различия между выводами типа Scala и С++ 11. В каких ситуациях я должен указывать типы на одном языке, но не в другом? Одно из отличий, похоже, является возвращаемым типом функций, которые всегда должны быть указаны в С++ 11, хотя decltype
и новый синтаксис функции с типом возвращаемого возвращаемого значения позволяют указать тип вывода.
Каковы различия между выводами типа Scala и С++ 11?
Ответ 1
С++ не может вызывать такие анонимные функции:
// this wont work*
void somefunc(std::vector<int>& v)
{
std::for_each(v.begin(), v.end(), [](auto &x) { x++; });
}
// /\
// ------ I want this to be infered
тогда как Scala может:
def somefunc(v: Vector[Int]) = v.map(x => x +1)
* Не уверен, что я правильно разобрался с синтаксисом кода на С++, я не оскорбляю язык, но он действительно загадочен. Если я допустил ошибку, исправьте меня, пожалуйста,
Ответ 2
По сути, вывод С++ упрощен по сравнению с взрослыми.
Функциональные языки обычно близки к Hindley/Milner, которые довольно близки к решению систем уравнений и позволяют иметь неизвестные по обеим сторонам забора.
Напротив, С++ ожидает, что сможет узнать тип любого внутреннего выражения и из него вывести тип внешнего выражения. Это строго один способ вывода, означающий, что:
auto x = foo(1, 2);
работает так, как ожидалось, пока есть foo
принимающие целые числа и возвращающие непустые. Однако, как продемонстрировано om-nom-nom:
foo(1, [](auto x) { ++x; });
Не будет работать, потому что вы не можете вернуться назад и использовать предполагаемый тип foo
для вывода типа лямбда.
Причина в том, что С++ использует перегрузки функций, что означает, что могут существовать несколько определений foo
, и вам действительно нужно знать типы аргументов для выбора правильного. Поскольку, как правило, вышеупомянутое выражение было бы неразрешимым, запрещено даже в ограниченном количестве случаев, когда ему было позволено избегать адвенции в будущем, и люди, никогда не зная, когда или нет, его можно использовать.